使用nodejs来模拟form表单进行文件上传,可以同时上传多个文件。
以前项目里有这个方法,最近在客户那里出问题了,同事说,这个方法从来就没管用过,SO,用了一天时间把这个方法给搞出来了(觉得花费的时间长了点),分享之。
代码及测试用例:
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 = '
----' + boundaryKey + '--';
var dataLength = 0;
var dataArr = new Array();
for (var i = 0; i < fileDataInfo.length; i++) {
var dataInfo = "
----" + boundaryKey + "
" + "Content-Disposition: form-data; name="" + fileDataInfo[i].urlKey + ""
" + 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 = "
----" + boundaryKey + "
" + "Content-Type: application/octet-stream
" + "Content-Disposition: form-data; name="" + fileKeyValue[i].urlKey + ""; filename="" + path.basename(fileKeyValue[i].urlValue) + ""
" + "Content-Transfer-Encoding: binary
";
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("
", '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('
')
}
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("
");
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方法,并遍历上传的文件将其保存在硬盘上了。
只是上传大文件会有问题,估计是需要服务器进行配置,暂且不管。
服务端方法(写在了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();
}
运行脚本:
node nodejsPostFile.js
运行结果:
示例下载