Node层模拟实现multipart表单的文件上传示例
程序员文章站
2022-09-04 08:50:56
有时候就是有这样的需求,nodejs做webserver,从浏览器端上传文件到后端服务器,node层只是做一个数据中转,如果在这个过程中,node webserver需要对...
有时候就是有这样的需求,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层的文件上传:
/** * 上传文件 * @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,大概思路:
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表单的文件上传示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
上一篇: sql join on 用法
下一篇: 大数据量,海量数据处理方法总结