使用nodejs来模拟form表单进行文件上传,能够同时上传多个文件。javascript
之前项目里有这个方法,最近在客户那里出问题了,同事说,这个方法历来就没管用过,SO,用了一天时间把这个方法给搞出来了(以为花费的时间长了点),分享之。html
代码及测试用例:java
var http = require('http'); var path = require('path'); var fs = require('fs'); function postFile(fileDataInfo, fileKeyValue, req) { var boundaryKey = Math.random().toString(16); var enddata = '\r\n----' + boundaryKey + '--'; var dataLength = 0; var dataArr = new Array(); for (var i = 0; i < fileDataInfo.length; i++) { var dataInfo = "\r\n----" + boundaryKey + "\r\n" + "Content-Disposition: form-data; name=\"" + fileDataInfo[i].urlKey + "\"\r\n\r\n" + fileDataInfo[i].urlValue; var dataBinary = new Buffer(dataInfo, "utf-8"); dataLength += dataBinary.length; dataArr.push({ dataInfo: dataInfo }); } var files = new Array(); for (var i = 0; i < fileKeyValue.length; i++) { var content = "\r\n----" + boundaryKey + "\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Disposition: form-data; name=\"" + fileKeyValue[i].urlKey + "\"; filename=\"" + path.basename(fileKeyValue[i].urlValue) + "\"\r\n" + "Content-Transfer-Encoding: binary\r\n\r\n"; var contentBinary = new Buffer(content, 'utf-8'); //当编码为ascii时,中文会乱码。 files.push({ contentBinary: contentBinary, filePath: fileKeyValue[i].urlValue }); } var contentLength = 0; for (var i = 0; i < files.length; i++) { var filePath = files[i].filePath; if (fs.existsSync(filePath)) { var stat = fs.statSync(filePath); contentLength += stat.size; } else { contentLength += new Buffer("\r\n", 'utf-8').length; } contentLength += files[i].contentBinary.length; } req.setHeader('Content-Type', 'multipart/form-data; boundary=--' + boundaryKey); req.setHeader('Content-Length', dataLength + contentLength + Buffer.byteLength(enddata)); // 将参数发出 for (var i = 0; i < dataArr.length; i++) { req.write(dataArr[i].dataInfo) //req.write('\r\n') } var fileindex = 0; var doOneFile = function() { req.write(files[fileindex].contentBinary); var currentFilePath = files[fileindex].filePath; if (fs.existsSync(currentFilePath)) { var fileStream = fs.createReadStream(currentFilePath, {bufferSize: 4 * 1024}); fileStream.pipe(req, {end: false}); fileStream.on('end', function() { fileindex++; if (fileindex == files.length) { req.end(enddata); } else { doOneFile(); } }); } else { req.write("\r\n"); fileindex++; if (fileindex == files.length) { req.end(enddata); } else { doOneFile(); } } }; if (fileindex == files.length) { req.end(enddata); } else { doOneFile(); } } //测试用例 //http://nodejs.org/api/http.html#http_http_request_options_callback var fileDataInfo = [ {urlKey: "abc", urlValue: "空格 中文"}, {urlKey: "def", urlValue: "asdfasfs123477"} ] var files = [ {urlKey: "file1", urlValue: "E:\\1.jpg"}, {urlKey: "file2", urlValue: "文件不存在"}, {urlKey: "file3", urlValue: ""}, {urlKey: "file4", urlValue: ""}, {urlKey: "file5", urlValue: "E:\\Pro 中文 空格.mp3"}, {urlKey: "file6", urlValue: "E:\\DFBF.jpg"}, {urlKey: "file7", urlValue: ""} ] var options = { host: "localhost", port: "8908", method: "POST", path: "/Home/Upload" } var req = http.request(options, function(res) { console.log("RES:" + res); console.log('STATUS: ' + res.statusCode); console.log('HEADERS: ' + JSON.stringify(res.headers)); //res.setEncoding("utf8"); res.on("data", function(chunk) { console.log("BODY:" + chunk); }) }) req.on('error', function(e) { console.log('problem with request:' + e.message); console.log(e); }); postFile(fileDataInfo, files, req); console.log("done");
服务端测试,用mvc在home控制器写了个upload方法,并遍历上传的文件将其保存在硬盘上了。node
只是上传大文件会有问题,估计是须要服务器进行配置,暂且无论。api
服务端方法(写在了Home控制器下)服务器
[HttpPost] public string Upload() { foreach (string file in this.Request.Files) { string strFileName = this.Request.Files[file].FileName; if (string.IsNullOrEmpty(strFileName)) continue; this.Request.Files[file].SaveAs(@"E:\新建文件夹\" + strFileName); } StringBuilder sb = new StringBuilder(); foreach (string item in this.Request.Form.AllKeys) { sb.AppendLine(string.Format("key:{0} value:{1}", item, this.Request.Form[item])); } sb.AppendLine(@"保存成功 路径:E:\新建文件夹\"); return sb.ToString(); }
运行脚本:mvc
node nodejsPostFile.js
运行结果:app
示例下载dom