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 相关文章推荐
javascript引用对象的方法
Jan 11 Javascript
Javascript 解疑
Nov 11 Javascript
jQuery validate 中文API 附validate.js中文api手册
Jul 31 Javascript
jQuery之字体大小的设置方法
Feb 27 Javascript
jquery 选取方法都有哪些
May 18 Javascript
AngularJS基础 ng-focus 指令简单示例
Aug 01 Javascript
vue.js入门教程之基础语法小结
Sep 01 Javascript
jQuery插件FusionCharts绘制的2D双面积图效果示例【附demo源码】
Apr 11 jQuery
基于JavaScript实现五子棋游戏
Aug 26 Javascript
JavaScript中concat复制数组方法浅析
Jan 20 Javascript
layui当点击文本框时弹出选择框,显示选择内容的例子
Sep 02 Javascript
JavaScript实现京东快递单号查询
Nov 30 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
福利彩票幸运号码自动生成器
2006/10/09 PHP
PHP垃圾回收机制引用计数器概念分析
2013/06/24 PHP
PHP中Fatal error session_start()错误解决步骤
2014/08/05 PHP
PHP中异常处理的一些方法整理
2015/07/03 PHP
CentOS 7.2 下编译安装PHP7.0.10+MySQL5.7.14+Nginx1.10.1的方法详解(mini版本)
2016/09/01 PHP
PHP+mysql实现从数据库获取下拉树功能示例
2017/01/06 PHP
PHP程序员学习使用Swoole的理由
2018/06/24 PHP
Yii 框架使用Forms操作详解
2020/05/18 PHP
Iframe 自适应高度并实时监控高度变化的js代码
2009/10/30 Javascript
Jquery跨域获得Json时invalid label错误的解决办法
2011/01/11 Javascript
jquery 实现二级/三级/多级联动菜单的思路及代码
2013/04/08 Javascript
JS+flash实现chrome和ie浏览器下同时可以复制粘贴
2013/09/22 Javascript
提升PHP安全:8个必须修改的PHP默认配置
2014/11/17 Javascript
jQuery中position()方法用法实例
2015/01/16 Javascript
浅析AngularJS Filter用法
2015/12/28 Javascript
javaScript嗅探执行神器-sniffer.js
2017/02/14 Javascript
利用JS制作万年历的方法
2017/08/16 Javascript
vue resource post请求时遇到的坑
2017/10/19 Javascript
微信小程序App生命周期详解
2018/01/31 Javascript
vue的全局提示框组件实例代码
2018/02/26 Javascript
动态内存分配导致影响Javascript性能的问题
2018/12/18 Javascript
使用mixins实现elementUI表单全局验证的解决方法
2019/04/02 Javascript
使用JavaScript计算前一天和后一天的思路详解
2019/12/20 Javascript
详解Vue 数据更新了但页面没有更新的 7 种情况汇总及延伸总结
2020/05/28 Javascript
python开发中module模块用法实例分析
2015/11/12 Python
python 使用值来排序一个字典的方法
2018/11/16 Python
python图形工具turtle绘制国际象棋棋盘
2019/05/23 Python
pycharm中import呈现灰色原因的解决方法
2020/03/04 Python
Django Model层F,Q对象和聚合函数原理解析
2020/11/12 Python
LivingSocial爱尔兰:爱尔兰本地优惠
2018/08/10 全球购物
澳大利亚在线高跟鞋商店:Shoe Me
2019/11/19 全球购物
What is the purpose of Void class? Void类的作用是什么?
2016/10/31 面试题
贸易跟单员英文求职信
2014/04/19 职场文书
树转促学习心得体会
2014/09/10 职场文书
社区党风廉政建设调研报告
2015/01/01 职场文书
学习党章心得体会2016
2016/01/15 职场文书