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


Posted in Javascript onJanuary 02, 2018

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

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

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

屏幕快照 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表单的文件上传示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
选择TreeView控件的树状数据节点的JS方法(jquery)
Feb 06 Javascript
有道JavaScript监听浏览器的问题
Jun 23 Javascript
JQuery学习笔记 nt-child的使用
Jan 17 Javascript
返回上一页并自动刷新的JavaScript代码
Feb 19 Javascript
javascript返回顶部的按钮实现方法
Jan 09 Javascript
JavaScript实现弹出模态窗体并接受传值的方法
Feb 12 Javascript
VUE2.0+ElementUI2.0表格el-table实现表头扩展el-tooltip
Nov 30 Javascript
angular6根据environments配置文件更改开发所需要的环境的方法
Mar 06 Javascript
Vue中util的工具函数实例详解
Jul 08 Javascript
vue仿淘宝滑动验证码功能(样式模仿)
Dec 10 Javascript
解决VUE项目localhost端口服务器拒绝连接,只能用127.0.0.1的问题
Aug 14 Javascript
gojs实现蚂蚁线动画效果
Feb 18 Javascript
10行原生JS实现文字无缝滚动(超简单)
Jan 02 #Javascript
js原生实现移动端手指滑动轮播图效果的示例
Jan 02 #Javascript
vue父组件向子组件(props)传递数据的方法
Jan 02 #Javascript
基于wordpress的ajax写法详解
Jan 02 #Javascript
基于Vue的SPA动态修改页面title的方法(推荐)
Jan 02 #Javascript
jq.ajax+php+mysql实现关键字模糊查询(示例讲解)
Jan 02 #Javascript
使用async、enterproxy控制并发数量的方法详解
Jan 02 #Javascript
You might like
php download.php实现代码 跳转到下载文件(response.redirect)
2009/08/26 PHP
表单提交错误后返回内容消失问题的解决方法(PHP网站)
2015/10/20 PHP
thinkPHP统计排行与分页显示功能示例
2016/12/02 PHP
Docker配置PHP开发环境教程
2016/12/21 PHP
PHP使用pdo连接access数据库并循环显示数据操作示例
2018/06/05 PHP
CodeIgniter框架钩子机制实现方法【hooks类】
2018/08/21 PHP
JavaScript对象模型-执行模型
2008/04/28 Javascript
js动态修改整个页面样式达到换肤效果
2014/05/23 Javascript
jQuery实现表格展开与折叠的方法
2015/05/04 Javascript
angularjs在ng-repeat中使用ng-model遇到的问题
2016/01/21 Javascript
JavaScript html5 canvas绘制时钟效果(二)
2016/03/27 Javascript
9种使用Chrome Firefox 自带调试工具调试javascript技巧
2017/12/22 Javascript
Vuejs在v-for中,利用index来对第一项添加class的方法
2018/03/03 Javascript
Angular如何在应用初始化时运行代码详解
2018/06/11 Javascript
JQuery常用简单动画操作方法回顾与总结
2019/12/07 jQuery
vue基于Echarts的拖拽数据可视化功能实现
2020/12/04 Vue.js
Python的Flask开发框架简单上手笔记
2015/11/16 Python
尝试用最短的Python代码来实现服务器和代理服务器
2016/06/23 Python
Python实现翻转数组功能示例
2018/01/12 Python
python字符串常用方法
2018/06/14 Python
python基于pdfminer库提取pdf文字代码实例
2019/08/15 Python
python编程进阶之类和对象用法实例分析
2020/02/21 Python
在python3中实现查找数组中最接近与某值的元素操作
2020/02/29 Python
Django实现图片上传功能步骤解析
2020/04/22 Python
open_basedir restriction in effect. 原因与解决方法
2021/03/14 PHP
Sephora丝芙兰澳洲官方网站:国际知名化妆品购物
2016/10/27 全球购物
viagogo英国票务平台:演唱会、体育比赛、戏剧门票
2017/03/24 全球购物
Orlebar Brown官网:设计师泳裤和泳装
2020/12/08 全球购物
大学生学习生活的自我评价
2013/11/01 职场文书
职业培训师职业生涯规划
2014/02/18 职场文书
小学班主任事迹材料
2014/12/17 职场文书
初中班干部工作总结
2015/08/10 职场文书
中学教代会开幕词
2016/03/04 职场文书
如何利用python和DOS获取wifi密码
2021/03/31 Python
springboot+WebMagic+MyBatis爬虫框架的使用
2021/08/07 Java/Android
阿里云k8s服务升级时502错误 springboot项目应用
2022/04/09 Servers