Node层模拟实现multipart表单的文件上传示例

有时候就是有这样的需求,Nodejs做webserver,从浏览器端上传文件到后端服务器,Node层只是做一个数据中转,如果在这个过程中,Node webserver需要对数据进行适当加工,然后再Post到后端,那么就得在Node层模拟文件上传了。

首先,通过浏览器上传文件,PostData格式是长着个样子的:

屏幕快照 2014-11-22 下午9.18.45.png

如图,每一组数据其实就是用“-----WebkitFormBoundary.....”分隔开的,最后再用这个分隔符结束,而且,这个分隔符完全是可自定义的。

每一段提交数据,则通过Content-disposition来描述,未指定Content-Type,则认text/plain,如果是上传的二进制文件,指定其mime-type即可。

简单封装一个方法,实现Node层的文件上传

rush:xhtml;"> /** * 上传文件 * @param files 经过formidable处理过的文件 * @param req httpRequest对象 * @param postData 额外提交的数据 */ function uploadFile(files,req,postData) { var boundaryKey = Math.random().toString(16); var endData = '\r\n----' + boundaryKey + '--'; var filesLength = 0,content;

// 初始数据,把post过来的数据都携带上去
content = (function (obj) {
var rslt = [];
Object.keys(obj).forEach(function (key) {
arr = ['\r\n----' + boundaryKey + '\r\n'];
arr.push('Content-disposition: form-data; name="' + key + '"\r\n\r\n');
arr.push(obj[key]);
rslt.push(arr.join(''));
});
return rslt.join('');
})(postData);

// 组装数据
Object.keys(files).forEach(function (key) {
if (!files.hasOwnProperty(key)) {
delete files.key;
return;
}
content += '\r\n----' + boundaryKey + '\r\n' +
'Content-Type: application/octet-stream\r\n' +
'Content-disposition: form-data; name="' + key + '"; ' +
'filename="' + files[key].name + '"; \r\n' +
'Content-transfer-encoding: binary\r\n\r\n';
files[key].contentBinary = new Buffer(content,'utf-8');
filesLength += files[key].contentBinary.length + fs.statSync(files[key].path).size;
});

req.setHeader('Content-Type','multipart/form-data; boundary=--' + boundaryKey);
req.setHeader('Content-Length',filesLength + Buffer.byteLength(endData));

// 执行上传
var allFiles = Object.keys(files);
var fileNum = allFiles.length;
var uploadedCount = 0;
allFiles.forEach(function (key) {
req.write(files[key].contentBinary);
var fileStream = fs.createReadStream(files[key].path,{bufferSize: 4 * 1024});
fileStream.on('end',function () {
// 上传成功一个文件之后,把临时文件删了
fs.unlink(files[key].path);
uploadedCount++;
if (uploadedCount == fileNum) {
// 如果已经是最后一个文件,那就正常结束
req.end(endData);
}
});
fileStream.pipe(req,{end: false});
});
}

思路就这样,代码也不复杂,可能额外需要注意的是,在http.request的response处理中,response.headers可能是gzip的,这个时候buffer不能直接toString,需要通过zlib解码再转换为string,大概思路:

rush:xhtml;"> var result = []; response.on('data',function (chunk) { result.push(chunk); });

// 处理response
var _dealResponse = function (data) {
var buffer = data;
try {
data = data.toString('utf8');
data = data ? (JSON.parse(data) || data) : false;
} catch (err) {
// 接口返回数据格式异常,解析失败
console.log(err);
}

self.res.writeHead(response.statusCode,'OK',{
'content-type': 'text/plain; charset=utf-8','content-length': buffer.length
});
self.res.write(buffer);
self.res.end();
};

response.on('end',function () {
result = Buffer.concat(result);
// gzip 的数据,需要zlib解码
if (response.headers['content-encoding'] == 'gzip') {
zlib.gunzip(result,function (err,dezipped) {
var data = err ? new Buffer('{}') : dezipped;
_dealResponse(data);
});
} else {
_dealResponse(result);
}
});

Mark一下,也许你路过正好需要~~~

以上这篇Node层模拟实现multipart表单的文件上传示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持编程之家。

相关文章

这篇文章主要介绍“基于nodejs的ssh2怎么实现自动化部署”的...
本文小编为大家详细介绍“nodejs怎么实现目录不存在自动创建...
这篇“如何把nodejs数据传到前端”文章的知识点大部分人都不...
本文小编为大家详细介绍“nodejs如何实现定时删除文件”,内...
这篇文章主要讲解了“nodejs安装模块卡住不动怎么解决”,文...
今天小编给大家分享一下如何检测nodejs有没有安装成功的相关...