2017-06-13 153 views
1

我想上傳文件到使用Multer的Node後端。 Multer要求表單以特定方式提交。如果未以這種方式提交,request.file參數將爲undefined。我創造了一種通過使用暴力的方法。該工作方式是這樣的:通過FormData上傳文件

指數1.HTML:

<form method="POST" enctype="multipart/form-data" id="fileUploadForm"> 
    <input type="file" id="selectedFile" name="selectedFile" /><br/><br/> 
    <input type="submit" value="Submit" id="btnSubmit"/> 
</form> 
... 
var btn = document.getElementById('btnSubmit'); 
btn.addEventListener('click', function(e) { 
    e.preventDefault(); 

    var form = $('#fileUploadForm')[0]; 
    var data = new FormData(form); 
    console.log(data); 

    $.ajax({ 
    type: "POST", 
    enctype: 'multipart/form-data', 
    url: "/upload", 
    data: data, 
    processData: false, 
    contentType: false, 
    cache: false, 
    timeout: 600000, 
    success: function (data) { 
     console.log("SUCCESS!"); 
    }, 
    error: function (e) { 
     console.log("ERROR : ", e); 
    } 
    }); 
});   

上面的代碼文件成功發佈到我的服務器。該服務器有以下幾點:

server.js

app.post('/upload', upload.single('selectedFile'), function(req, res) { 
    if (req.file) { 
    console.log('file uploaded'); 
    } else { 
    console.log('no file'); 
    } 

    res.send({}); 
}); 

使用上面的代碼,「上傳的文件」如預期顯示在控制檯窗口。但是,我需要一個更有活力的方法。出於這個原因,我需要以編程方式在JavaScript中構建表單。在試圖做到這一點,我創建了以下內容:

指數2.HTML [我的UI]

var btn = document.getElementById('btnSubmit'); 
btn.addEventListener('click', function(e) { 
    var form = document.createElement('form'); 
    form.action = '/upload'; 
    form.method = 'POST'; 
    form.enctype = 'multipart/form-data'; 

    var node = document.createElement("input");       
    node.name = 'selectedFile'; 
    node.value = GLOBAL_SELECTED_FILE; 
    form.appendChild(node); 

    var data = new FormData(form); 
    data.append('id', this.id); 
    console.log(data); 

    $.ajax({ 
    type: 'POST', 
    url: '/profile-picture/upload', 
    enctype: 'multipart/form-data',       
    data: data,        
    contentType: false, 
    processData: false, 
    success: function(res) { 
     console.log('success!'); 
    }, 
    error: function(xhr, status, err) { 
     console.log('error'); 
    } 
    }); 
}); 

這第二種方法是行不通的。爲了澄清,GLOBAL_SELECTED_FILE變量是從輸入元素中選擇的文件的數據。數據通過FileReader API加載。看起來像這樣:

var GLOBAL_SELECTED_FILE = null; 

var fileReader = new FileReader();  
fileReader.onload = function(e) { 
    GLOBAL_SELECTED_FILE = e.target.result; 
} 
fileReader.readAsDataURL(fileSelected); // file selected comes from the onchange event on a <input type="file">..</input> element 

基本上,我正在加載圖像預覽。無論如何,當我點擊工作版本(index-1.html)中的提交按鈕時,我注意到在提琴手中,通過在index-2.html中發送的值發送了不同的值。

隨着指數1.HTML的方法,提琴手顯示在「的TextView」標籤是這樣的:

------WebKitFormBoundary183mBxXxf1HoE4Et 
Content-Disposition: form-data; name="selectedFile"; filename="picture.PNG" 
Content-Type: image/png 

PNG 

然而,當我照「的TextView」選項卡中的提琴手發送的數據通過index-2.html,我看到以下內容:

------WebKitFormBoundary9UHBP02of1OI5Zb6 
Content-Disposition: form-data; name="selectedFile" 

data:image/png;base64,iVBORw0KGg[A LOT MORE TO GO] 

這就像FormData對同一個值使用兩種不同的編碼。然而,我不明白爲什麼。如何獲得index-2.html以與index-1.html相同的格式發送圖像,以便Multer將填充req.file屬性?

謝謝!

回答

0

在索引1.HTML,使用的是一個文件輸入:

<input type="file" id="selectedFile" name="selectedFile" /> 

在索引2.HTML,要創建一個普通形式的輸入(而不是一個文件輸入):

var node = document.createElement("input");       
node.name = 'selectedFile'; 
node.value = GLOBAL_SELECTED_FILE; 
form.appendChild(node); 

要創建文件輸入,您需要添加node.type = 'file'。但是,您將無法設置,因爲browser security restrictions prevent setting the value of file inputs.

相反,你需要做的是追加,是由用戶選擇的FormData對象的文件中值:

var data = new FormData(form); 
data.append('id', this.id); 
data.append('selectedFile', $('#fileInputElement')[0].files[0]);