使用 FormData 和 multer 上传文件
Uploading a file with FormData and multer
我已经成功地使用 multer
模块将文件上传到节点服务器,方法是使用输入文件对话框选择文件,然后提交表单,但现在我需要,而不是提交表单,创建一个 FormData
对象,并使用 XMLHttpRequest
发送文件,但它不起作用,文件总是 undefined
在服务器端(路由器)。
执行 AJAX 请求的函数是:
function uploadFile(fileToUpload, url) {
var form_data = new FormData();
form_data.append('track', fileToUpload, fileToUpload.name);
// This function simply creates an XMLHttpRequest object
// Opens the connection and sends form_data
doJSONRequest("POST", "/tracks/upload", null, form_data, function(d) {
console.log(d);
})
}
请注意,fileToUpload
已定义并且 url
是正确的,因为调用了正确的路由器方法。 fileToUpload
是一个 File
对象,通过将文件从文件系统拖放到拖放区,然后通过访问拖放事件的 dataTransfer
属性 获得。
doJSONRequest
是一个创建 XMLHttpRequest
对象并发送文件等的函数(如评论中所述)。
function doJSONRequest(method, url, headers, data, callback){
//all the arguments are mandatory
if(arguments.length != 5) {
throw new Error('Illegal argument count');
}
doRequestChecks(method, true, data);
//create an ajax request
var r = new XMLHttpRequest();
//open a connection to the server using method on the url API
r.open(method, url, true);
//set the headers
doRequestSetHeaders(r, method, headers);
//wait for the response from the server
r.onreadystatechange = function () {
//correctly handle the errors based on the HTTP status returned by the called API
if (r.readyState != 4 || (r.status != 200 && r.status != 201 && r.status != 204)){
return;
} else {
if(isJSON(r.responseText))
callback(JSON.parse(r.responseText));
else if (callback !== null)
callback();
}
};
//set the data
var dataToSend = null;
if (!("undefined" == typeof data)
&& !(data === null))
dataToSend = JSON.stringify(data);
//console.log(dataToSend)
//send the request to the server
r.send(dataToSend);
}
这里是 doRequestSetHeaders
:
function doRequestSetHeaders(r, method, headers){
//set the default JSON header according to the method parameter
r.setRequestHeader("Accept", "application/json");
if(method === "POST" || method === "PUT"){
r.setRequestHeader("Content-Type", "application/json");
}
//set the additional headers
if (!("undefined" == typeof headers)
&& !(headers === null)){
for(header in headers){
//console.log("Set: " + header + ': '+ headers[header]);
r.setRequestHeader(header, headers[header]);
}
}
}
而我的路由器上传文件是这样的
// Code to manage upload of tracks
var multer = require('multer');
var uploadFolder = path.resolve(__dirname, "../../public/tracks_folder");
function validTrackFormat(trackMimeType) {
// we could possibly accept other mimetypes...
var mimetypes = ["audio/mp3"];
return mimetypes.indexOf(trackMimeType) > -1;
}
function trackFileFilter(req, file, cb) {
cb(null, validTrackFormat(file.mimetype));
}
var trackStorage = multer.diskStorage({
// used to determine within which folder the uploaded files should be stored.
destination: function(req, file, callback) {
callback(null, uploadFolder);
},
filename: function(req, file, callback) {
// req.body.name should contain the name of track
callback(null, file.originalname);
}
});
var upload = multer({
storage: trackStorage,
fileFilter: trackFileFilter
});
router.post('/upload', upload.single("track"), function(req, res) {
console.log("Uploaded file: ", req.file); // Now it gives me undefined using Ajax!
res.redirect("/"); // or /#trackuploader
});
我的猜测是 multer
不理解 fileToUpload
是一个名为 track
的文件(不是吗?),即中间件 upload.single("track")
是working/parsing 不正确或什么都没有,或者它可能根本不适用于 FormData
,在那种情况下它会一团糟。继续使用 multer 的替代方案是什么?
如何使用 AJAX 和 multer 上传文件?
如果您需要更多详细信息,请随时询问。
multer 使用 multipart/form-data
内容类型请求上传文件。从你的 doRequestSetHeaders
函数中删除这个位应该可以解决你的问题:
if(method === "POST" || method === "PUT"){
r.setRequestHeader("Content-Type", "application/json");
}
您不需要指定 content-type
,因为 FormData
对象已经使用了正确的编码类型。来自 docs:
The transmitted data is in the same format that the form's submit()
method would use to send the data if the form's encoding type were set
to multipart/form-data.
这是一个工作示例。它假定有一个 ID 为 drop-zone
的拖放区和一个 ID 为 upload-button
:
的上传按钮
var dropArea = document.getElementById("drop-zone");
var uploadBtn = document.getElementById("upload-button");
var files = [];
uploadBtn.disabled = true;
uploadBtn.addEventListener("click", onUploadClick, false);
dropArea.addEventListener("dragenter", prevent, false);
dropArea.addEventListener("dragover", prevent, false);
dropArea.addEventListener("drop", onFilesDropped, false);
//----------------------------------------------------
function prevent(e){
e.stopPropagation();
e.preventDefault();
}
//----------------------------------------------------
function onFilesDropped(e){
prevent(e);
files = e.dataTransfer.files;
if (files.length){
uploadBtn.disabled = false;
}
}
//----------------------------------------------------
function onUploadClick(e){
if (files.length){
sendFile(files[0]);
}
}
//----------------------------------------------------
function sendFile(file){
var formData = new FormData();
var xhr = new XMLHttpRequest();
formData.append("track", file, file.name);
xhr.open("POST", "http://localhost:3000/tracks/upload", true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.send(formData);
}
服务器端代码是一个简单的快速应用程序,具有您提供的确切路由器代码。
到post一个被multer接受的FormData对象上传函数应该是这样的:
function uploadFile(fileToUpload, url) {
var formData = new FormData();
//append file here
formData.append('file', fileToUpload, fileToUpload.name);
//and append the other fields as an object here
/* var user = {name: 'name from the form',
email: 'email from the form'
etc...
}*/
formData.append('user', user);
// This function simply creates an XMLHttpRequest object
// Opens the connection and sends form_data
doJSONRequest("POST", "/tracks/upload", null, formData, function(d) {
console.log(d);
})
}
我已经成功地使用 multer
模块将文件上传到节点服务器,方法是使用输入文件对话框选择文件,然后提交表单,但现在我需要,而不是提交表单,创建一个 FormData
对象,并使用 XMLHttpRequest
发送文件,但它不起作用,文件总是 undefined
在服务器端(路由器)。
执行 AJAX 请求的函数是:
function uploadFile(fileToUpload, url) {
var form_data = new FormData();
form_data.append('track', fileToUpload, fileToUpload.name);
// This function simply creates an XMLHttpRequest object
// Opens the connection and sends form_data
doJSONRequest("POST", "/tracks/upload", null, form_data, function(d) {
console.log(d);
})
}
请注意,fileToUpload
已定义并且 url
是正确的,因为调用了正确的路由器方法。 fileToUpload
是一个 File
对象,通过将文件从文件系统拖放到拖放区,然后通过访问拖放事件的 dataTransfer
属性 获得。
doJSONRequest
是一个创建 XMLHttpRequest
对象并发送文件等的函数(如评论中所述)。
function doJSONRequest(method, url, headers, data, callback){
//all the arguments are mandatory
if(arguments.length != 5) {
throw new Error('Illegal argument count');
}
doRequestChecks(method, true, data);
//create an ajax request
var r = new XMLHttpRequest();
//open a connection to the server using method on the url API
r.open(method, url, true);
//set the headers
doRequestSetHeaders(r, method, headers);
//wait for the response from the server
r.onreadystatechange = function () {
//correctly handle the errors based on the HTTP status returned by the called API
if (r.readyState != 4 || (r.status != 200 && r.status != 201 && r.status != 204)){
return;
} else {
if(isJSON(r.responseText))
callback(JSON.parse(r.responseText));
else if (callback !== null)
callback();
}
};
//set the data
var dataToSend = null;
if (!("undefined" == typeof data)
&& !(data === null))
dataToSend = JSON.stringify(data);
//console.log(dataToSend)
//send the request to the server
r.send(dataToSend);
}
这里是 doRequestSetHeaders
:
function doRequestSetHeaders(r, method, headers){
//set the default JSON header according to the method parameter
r.setRequestHeader("Accept", "application/json");
if(method === "POST" || method === "PUT"){
r.setRequestHeader("Content-Type", "application/json");
}
//set the additional headers
if (!("undefined" == typeof headers)
&& !(headers === null)){
for(header in headers){
//console.log("Set: " + header + ': '+ headers[header]);
r.setRequestHeader(header, headers[header]);
}
}
}
而我的路由器上传文件是这样的
// Code to manage upload of tracks
var multer = require('multer');
var uploadFolder = path.resolve(__dirname, "../../public/tracks_folder");
function validTrackFormat(trackMimeType) {
// we could possibly accept other mimetypes...
var mimetypes = ["audio/mp3"];
return mimetypes.indexOf(trackMimeType) > -1;
}
function trackFileFilter(req, file, cb) {
cb(null, validTrackFormat(file.mimetype));
}
var trackStorage = multer.diskStorage({
// used to determine within which folder the uploaded files should be stored.
destination: function(req, file, callback) {
callback(null, uploadFolder);
},
filename: function(req, file, callback) {
// req.body.name should contain the name of track
callback(null, file.originalname);
}
});
var upload = multer({
storage: trackStorage,
fileFilter: trackFileFilter
});
router.post('/upload', upload.single("track"), function(req, res) {
console.log("Uploaded file: ", req.file); // Now it gives me undefined using Ajax!
res.redirect("/"); // or /#trackuploader
});
我的猜测是 multer
不理解 fileToUpload
是一个名为 track
的文件(不是吗?),即中间件 upload.single("track")
是working/parsing 不正确或什么都没有,或者它可能根本不适用于 FormData
,在那种情况下它会一团糟。继续使用 multer 的替代方案是什么?
如何使用 AJAX 和 multer 上传文件?
如果您需要更多详细信息,请随时询问。
multer 使用 multipart/form-data
内容类型请求上传文件。从你的 doRequestSetHeaders
函数中删除这个位应该可以解决你的问题:
if(method === "POST" || method === "PUT"){
r.setRequestHeader("Content-Type", "application/json");
}
您不需要指定 content-type
,因为 FormData
对象已经使用了正确的编码类型。来自 docs:
The transmitted data is in the same format that the form's submit() method would use to send the data if the form's encoding type were set to multipart/form-data.
这是一个工作示例。它假定有一个 ID 为 drop-zone
的拖放区和一个 ID 为 upload-button
:
var dropArea = document.getElementById("drop-zone");
var uploadBtn = document.getElementById("upload-button");
var files = [];
uploadBtn.disabled = true;
uploadBtn.addEventListener("click", onUploadClick, false);
dropArea.addEventListener("dragenter", prevent, false);
dropArea.addEventListener("dragover", prevent, false);
dropArea.addEventListener("drop", onFilesDropped, false);
//----------------------------------------------------
function prevent(e){
e.stopPropagation();
e.preventDefault();
}
//----------------------------------------------------
function onFilesDropped(e){
prevent(e);
files = e.dataTransfer.files;
if (files.length){
uploadBtn.disabled = false;
}
}
//----------------------------------------------------
function onUploadClick(e){
if (files.length){
sendFile(files[0]);
}
}
//----------------------------------------------------
function sendFile(file){
var formData = new FormData();
var xhr = new XMLHttpRequest();
formData.append("track", file, file.name);
xhr.open("POST", "http://localhost:3000/tracks/upload", true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.send(formData);
}
服务器端代码是一个简单的快速应用程序,具有您提供的确切路由器代码。
到post一个被multer接受的FormData对象上传函数应该是这样的:
function uploadFile(fileToUpload, url) {
var formData = new FormData();
//append file here
formData.append('file', fileToUpload, fileToUpload.name);
//and append the other fields as an object here
/* var user = {name: 'name from the form',
email: 'email from the form'
etc...
}*/
formData.append('user', user);
// This function simply creates an XMLHttpRequest object
// Opens the connection and sends form_data
doJSONRequest("POST", "/tracks/upload", null, formData, function(d) {
console.log(d);
})
}