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 参考教程
Dec 29 Javascript
Javascript 入门基础学习
Mar 10 Javascript
Tab页界面 用jQuery及Ajax技术实现(php后台)
Oct 12 Javascript
jquery实现网站超链接和图片提示效果
Mar 21 Javascript
js对文章内容进行分页示例代码
Mar 05 Javascript
IE 下Enter提交表单存在重复提交问题的解决方法
May 04 Javascript
js数组操作常用方法
May 08 Javascript
JS实现DIV容器赋值的方法
Dec 14 Javascript
实例剖析AngularJS框架中数据的双向绑定运用
Mar 04 Javascript
微信小程序 火车票查询实例讲解
Oct 17 Javascript
简单了解JavaScript弹窗实现代码
May 07 Javascript
vue特效之翻牌动画
Apr 20 Vue.js
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模糊查询的实现方法(推荐)
2016/09/06 PHP
PHP编程计算文件或数组中单词出现频率的方法
2017/05/22 PHP
laravel在中间件内生成参数并且传递到控制器中的2种姿势
2019/10/15 PHP
js验证表单大全
2006/11/25 Javascript
JavaScript入门教程(10) 认识其他对象
2009/01/31 Javascript
javascript学习笔记(十一) 正则表达式介绍
2012/06/20 Javascript
js实现点击注册按钮开始读秒倒计时的小例子
2013/05/11 Javascript
jquery 滚动条事件简单实例
2013/07/12 Javascript
jquery()函数的三种语法介绍
2013/10/09 Javascript
jQuery多项选项卡的实现思路附样式及代码
2014/06/03 Javascript
js代码实现点击按钮出现60秒倒计时
2021/01/28 Javascript
基于JS实现新闻列表无缝向上滚动实例代码
2016/01/22 Javascript
js实现PC端和移动端刮卡效果
2020/03/27 Javascript
js实现简单的获取验证码按钮效果
2017/03/03 Javascript
详解vue-router 路由元信息
2017/09/13 Javascript
详解在vue-cli中使用路由
2017/09/25 Javascript
微信小程序绘制图片发送朋友圈
2019/07/25 Javascript
在vue中对数组值变化的监听与重新响应渲染操作
2020/07/17 Javascript
[01:02:03]2014 DOTA2华西杯精英邀请赛 5 24 NewBee VS VG
2014/05/26 DOTA
Python图像灰度变换及图像数组操作
2016/01/27 Python
基于Python实现一个简单的银行转账操作
2016/03/06 Python
Python数据结构之栈、队列的实现代码分享
2017/12/04 Python
Python 20行简单实现有道在线翻译的详解
2019/05/15 Python
python实现键盘输入的实操方法
2019/07/16 Python
解决pytorch-yolov3 train 报错的问题
2020/02/18 Python
Python基于os.environ从windows获取环境变量
2020/06/09 Python
Python轻量级web框架bottle使用方法解析
2020/06/13 Python
香港No.1得奖零食网:香港零食大王
2016/07/22 全球购物
Ryderwear澳洲官网:澳大利亚高端健身训练装备品牌
2018/09/18 全球购物
科颜氏香港官方网店:Kiehl’s香港
2021/03/07 全球购物
驾驶员培训方案
2014/05/01 职场文书
投标承诺书怎么写
2014/05/24 职场文书
办理房产证委托书
2014/09/18 职场文书
成都人事代理协议书
2014/10/25 职场文书
党的群众路线教育实践活动整改落实情况自查报告
2014/10/28 职场文书
门店店长岗位职责
2015/04/14 职场文书