通过 FormData 上传文件
Uploading File via FormData
我正在尝试将文件上传到使用 Multer 的节点后端。 Multer 要求以特定方式提交表单。如果不以这种方式提交,request.file
参数将为 undefined
。我创建了一种使用蛮力的方法。该工作方法如下所示:
索引-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({});
});
使用上面的代码,"file uploaded" 按预期显示在控制台 window 中。但是,我需要一种更动态的方法。因此,我需要以编程方式在 JavaScript 中构建表单。为了做到这一点,我创建了以下内容:
index-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) 中点击提交按钮时,我注意到在 Fiddler 中发送了一个不同的值,而不是在 index-2.html 中发送的值。
使用 index-1.html 中的方法,Fiddler 在 "TextView" 选项卡中显示如下内容:
------WebKitFormBoundary183mBxXxf1HoE4Et
Content-Disposition: form-data; name="selectedFile"; filename="picture.PNG"
Content-Type: image/png
PNG
但是,当我在 Fiddler 的 "TextView" 选项卡中查看通过索引-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 属性?
谢谢!
在索引-1.html中,您正在使用文件输入:
<input type="file" id="selectedFile" name="selectedFile" />
在 index-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]);
我正在尝试将文件上传到使用 Multer 的节点后端。 Multer 要求以特定方式提交表单。如果不以这种方式提交,request.file
参数将为 undefined
。我创建了一种使用蛮力的方法。该工作方法如下所示:
索引-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({});
});
使用上面的代码,"file uploaded" 按预期显示在控制台 window 中。但是,我需要一种更动态的方法。因此,我需要以编程方式在 JavaScript 中构建表单。为了做到这一点,我创建了以下内容:
index-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) 中点击提交按钮时,我注意到在 Fiddler 中发送了一个不同的值,而不是在 index-2.html 中发送的值。
使用 index-1.html 中的方法,Fiddler 在 "TextView" 选项卡中显示如下内容:
------WebKitFormBoundary183mBxXxf1HoE4Et
Content-Disposition: form-data; name="selectedFile"; filename="picture.PNG"
Content-Type: image/png
PNG
但是,当我在 Fiddler 的 "TextView" 选项卡中查看通过索引-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 属性?
谢谢!
在索引-1.html中,您正在使用文件输入:
<input type="file" id="selectedFile" name="selectedFile" />
在 index-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]);