我已成功设法使用该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
通过将文件从文件系统删除到dropzone,然后通过访问dataTransfer
drop事件的属性获得的对象.
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")
无法正常工作/解析或什么都没有,或者它可能根本无法使用FormData
,在这种情况下它会是一团糟.通过保持使用multer会有什么替代方案?
如何使用AJAX和multer上传文件?
不要犹豫,询问您是否需要更多细节.
multer使用multipart/form-data
内容类型的请求来上传文件.从您的doRequestSetHeaders
函数中删除此位应该可以解决您的问题:
if(method === "POST" || method === "PUT"){ r.setRequestHeader("Content-Type", "application/json"); }
您无需指定,content-type
因为FormData
对象已使用正确的编码类型.来自文档:
如果表单的编码类型设置为multipart/form-data,则传输的数据格式与表单的submit()方法用于发送数据的格式相同.
这是一个有效的例子.它假定有一个带有id的dropzone 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); }
服务器端代码是一个简单的快速应用程序,具有您提供的确切路由器代码.