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 相关文章推荐
JQuery AJAX实现目录浏览与编辑的代码
Oct 21 Javascript
js/ajax跨越访问-jsonp的原理和实例(javascript和jquery实现代码)
Dec 27 Javascript
php,js,css字符串截取的办法集锦
Sep 26 Javascript
Javascript的闭包详解
Dec 26 Javascript
JavaScript几种数组去掉重复值的方法推荐
Apr 12 Javascript
javascript中获取元素标签中间的内容的实现方法
Oct 08 Javascript
JS数字千分位格式化实现方法总结
Dec 16 Javascript
easy ui datagrid 从编辑框中获取值的方法
Feb 22 Javascript
浅谈Angular HttpClient简单入门
May 04 Javascript
利用jsonp解决js读取本地json跨域的问题
Dec 11 Javascript
javascript实现商品图片放大镜
Nov 28 Javascript
VUE+Element实现增删改查的示例源码
Nov 23 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
中英文字符串翻转函数
2008/12/09 PHP
ThinkPHP写第一个模块应用
2012/02/20 PHP
PHP 接入微信扫码支付总结(总结篇)
2016/11/03 PHP
PHP让数组中有相同值的组成新的数组实例
2017/12/31 PHP
php中html_entity_decode实现HTML实体转义
2018/06/13 PHP
JavaScript使用prototype定义对象类型(转)[
2006/12/22 Javascript
JavaScript 判断判断某个对象是Object还是一个Array
2010/01/28 Javascript
JQuery自适应IFrame高度(支持嵌套 兼容IE,ff,safafi,chrome)
2011/03/28 Javascript
基于jQuery的模仿新浪微博时间的组件
2011/10/04 Javascript
JS实现从连接中获取youtube的key实例
2015/07/02 Javascript
jQuery移动端日期(datedropper)和时间(timedropper)选择器附源码下载
2016/04/19 Javascript
JavaScript实现父子dom同时绑定两个点击事件,一个用捕获,一个用冒泡时执行顺序的方法
2017/03/30 Javascript
利用node.js制作命令行工具方法教程(一)
2017/06/22 Javascript
使用pkg打包Node.js应用的方法步骤
2018/10/19 Javascript
vue 搭建后台系统模块化开发详解
2019/05/01 Javascript
[46:32]Fnatic vs OG 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
基于循环神经网络(RNN)实现影评情感分类
2018/03/26 Python
pandas数据处理基础之筛选指定行或者指定列的数据
2018/05/03 Python
Python自定义函数实现求两个数最大公约数、最小公倍数示例
2018/05/21 Python
基于python实现聊天室程序
2018/07/27 Python
如何在VSCode上轻松舒适的配置Python的方法步骤
2019/10/28 Python
Python socket实现的文件下载器功能示例
2019/11/15 Python
python模拟实现分发扑克牌
2020/04/22 Python
使用postMessage让 iframe自适应高度的方法示例
2019/10/08 HTML / CSS
亚马逊巴西站:Amazon.com.br
2019/09/22 全球购物
注塑工厂厂长岗位职责
2013/12/02 职场文书
大众服装店创业计划书范文
2014/01/01 职场文书
甜品店的创业计划书范文
2014/01/02 职场文书
会计专业应届生自荐信
2014/02/07 职场文书
大学生个人求职口试自我评价
2014/02/16 职场文书
事业单位个人总结
2015/02/12 职场文书
库房管理员岗位职责
2015/02/12 职场文书
地雷战观后感
2015/06/09 职场文书
Windows 11要来了?微软文档揭示Win11太阳谷 / Win10有两个不同版本
2021/11/21 数码科技
使用opencv-python如何打开USB或者笔记本前置摄像头
2022/06/21 Python
css中:last-child不生效的解决方法
2022/08/05 HTML / CSS