ColdFusion无法读取Ajax发送的FormData

MPa*_*aul 5 ajax coldfusion jquery file-upload jquery-file-upload

我正在创建一个文件上传组件,可以将其<cfinclude>上传到任何 CFM 页面上,该组件允许标准文件选择和拖放功能。

选择文件并提交表单时,没有问题,因为我的 ColdFusion 代码依赖于表单范围来检索文件。

为了使用拖放功能发送文件,我使用 jQuery 通过 Ajax 发送FormData基于当前表单的请求。

$form.on('submit', function(e) {
    e.preventDefault();

    // Get FormData based on form and append the dragged and dropped files 
    var ajaxData = new FormData($form.get(0));
    if (droppedFiles) {
        $.each(droppedFiles, function(i, file) {
            ajaxData.append($('input[type=file]').attr('name'), file);
        });
    }

    $.ajax({
        url: $form.attr('action'),
        type: $form.attr('method'),
        cache: false,
        contentType:false,
        processData: false,
        success: function(data) {
            if (data.SUCCESS) uploadSuccessful($form);
            else
            {
                console.error(data.ERROR);
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.error('Error: File upload unsuccessful ' + errorThrown);
        },
        data: ajaxData,
        dataType: 'json',
        dataFilter: function(data, type){ 
            return data.substring(2, data.length); 
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

HTML:

<form class="file-upload-container" method="post" action="upload.cfm" enctype="multipart/form-data">
    <label class="file-upload-input">
        <i class="fa fa-upload" aria-hidden="true" style="font-size:5em;"></i><br/><br/>
        <input type="file" name="attachment" id="attachment" />
    </label>
    <div class="file-upload-controls">
        <input type="button" id="cancelUpload" value="Cancel" class="btn btn-green" />
        <input type="submit" id="upload" value="Upload" class="btn btn-green" />
    </div>
</form>
Run Code Online (Sandbox Code Playgroud)

action的目的是<form>发布到我的upload.cfm页面。

我首先验证发布的表单是否包含名为“attachment”的元素:

<cfif structKeyExists(form, "attachment")>
    <!--- This always passes since I'm posting the form with the submit button --->
</cfif>
Run Code Online (Sandbox Code Playgroud)

然后,我尝试检索文件名,以便可以与接受的文件类型进行比较、上传文件、重命名文件并将条目插入数据库。FormData我遇到的问题是当我尝试从发布的对象(甚至整个文件的内容......)获取文件名时。

<cffunction name="GetTheFileName" access="public" returntype="string" output="false" >
    <cfargument name="fieldName" required="true" type="string" hint="Name of the Form field" />

    <cfset var tmpPartsArray = Form.getPartsArray() />

    <cfif IsDefined("tmpPartsArray")>
        <cfloop array="#tmpPartsArray#" index="local.tmpPart">
            <cfif local.tmpPart.isFile() AND local.tmpPart.getName() EQ arguments.fieldName> 
                <cfreturn LCase(local.tmpPart.getFileName()) />
            </cfif>
        </cfloop>
    </cfif>
    <cfreturn "" />
</cffunction>
Run Code Online (Sandbox Code Playgroud)

该行Form.getPartsArray()返回一个数组,但数组中的值是空的。(例如,文件路径:'',文件名:'')

这让我相信,无论 ajax 是否将其作为多部分/表单数据FormData发布,它的行为方式都与发布的实际表单不同。FormData

问题

  1. 为了读取FormDataColdFusion 端的对象以检索文件名,我缺少什么。

  2. 表单范围如何有效地利用已发布的内容,FormData就好像它是实际<form>发布的一样。

研究

来源表明我可以使用 Java 的 FileOutputStream 读取文件。(这不是一个理想的解决方案,因为我还允许典型的“选择文件”,它已经利用了表单范围)

MPa*_*aul 1

我找到了一个解决方案,尽管不是我最初希望的解决方案。

根据我的观察,ColdFusion 对待FormData对象的方式与实际表单发布的方式不同。当表单范围不包含表单数据时,这一点很明显。

相反,我必须以不同的方式处理通过拖放功能发布的数据。

按照建议的上传文件块的方法(源代码),我upload.cfm通过 ajax 请求页面,其中 Content-Type 与要上传的文件的 MimeType 匹配,实际上传使用该类java.io.FileOutputStream将文件写入磁盘。

JavaScript + AJAX:

var droppedFiles; // Assuming droppedFiles was populated during the 'drop' event

// Get the Form and FormData (although FormData won't be used when files are Dragged  & Dropped)
var $form = $('.file-upload-container');
var ajaxData = new FormData($(form).get(0));

var dragged = false;                
var filesToBeUploaded = document.getElementById("attachment");  
var file = filesToBeUploaded.files[0]; 
if (droppedFiles){file = droppedFiles;dragged=true;}

$.ajax({
    url: $form.attr('action'),
    type: $form.attr('method'),
    cache: false,
    contentType: dragged ? file.type : false,
    processData: false,
    success: function(data) {
        if (data.SUCCESS) { // Do stuff }
        else
        {
            // Do stuff
            console.error(data.ERROR);
        }
    },
    error: function(jqXHR, textStatus, errorThrown) {
        console.error('Error: File upload unsuccessful ' + errorThrown);
    },
    data: dragged ? file : ajaxData,
    dataType: 'json',
    dataFilter: function(data, type){ 
        return data.substring(2, data.length); 
    },
    headers: { 'X_FILE_NAME': dragged ? file.name : "", 'X_CONTENT_TYPE': dragged ? file.type : "" }
});
Run Code Online (Sandbox Code Playgroud)

冷聚变:

<cfset bUseFormData = false />

<cfset headerData = getHTTPRequestData().headers>
<cfif structKeyExists(headerData, "X_FILE_NAME") AND ("#headerData.X_FILE_NAME#" NEQ "")>
    <cfset bUseFormData = true />        
</cfif>

<cfif structKeyExists(form, "attachment") OR bUseFormData>

    <cfif bUseFormData>
        <cfset content = getHTTPRequestData().content>
        <cfset filePath = "#Application.AdminUploadPath#\" & "#headerData.X_CONTENT_TYPE#">
        <cfset fos = createObject("java", "java.io.FileOutputStream").init(filePath, true)>
        <cfset fos.write(content)>
        <cfset fos.close()>
    <cfelse>
        <cffile action="UPLOAD" filefield="form.attachment" destination="#Application.AdminUploadPath#">
    </cfif>

</cfif>
Run Code Online (Sandbox Code Playgroud)

为了简单起见,我排除了验证文件扩展名、MimeType 和错误处理的代码。