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中的107个基础知识收集整理 推荐
Mar 29 Javascript
FireFox下XML对象转化成字符串的解决方法
Dec 09 Javascript
JavaScript中instanceof与typeof运算符的用法及区别详细解析
Nov 19 Javascript
JavaScript模拟深蓝vs卡斯帕罗夫的国际象棋对局示例
Apr 22 Javascript
jQuery移动页面开发中的触摸事件与虚拟鼠标事件简介
Dec 03 Javascript
javascript检测移动设备横竖屏
May 21 Javascript
AngularJS 中文API参考手册
Jul 28 Javascript
Node.js的文件权限及读写flag详解
Oct 11 Javascript
简单说说angular.json文件的使用
Oct 29 Javascript
webpack自动打包和热更新的实现方法
Jun 24 Javascript
jQuery实现影院选座订座效果
Apr 13 jQuery
Javascript的promise,async和await的区别详解
Mar 24 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类
2008/04/09 PHP
php读取mysql的简单实例
2014/01/15 PHP
PHP入门教程之表单与验证实例详解
2016/09/11 PHP
jQuery 顺便学习下CSS选择器 奇偶匹配nth-child(even)
2010/05/24 Javascript
简单实用的js调试logger组件实现代码
2010/11/20 Javascript
使用GruntJS链接与压缩多个JavaScript文件过程详解
2013/08/02 Javascript
JS刷新当前页面的几种方法总结
2013/12/24 Javascript
JavaScript及jquey实现多个数组的合并操作
2014/09/06 Javascript
前端轻量级MVC框架CanJS详解
2014/09/26 Javascript
js实现文字闪烁特效的方法
2015/12/17 Javascript
jQuery点击输入框显示验证码图片
2016/05/19 Javascript
jQueryUI 拖放排序遇到滚动条时有可能无法执行排序的小bug及解决方案
2016/12/19 Javascript
node.js(express)中使用Jcrop进行图片剪切上传功能
2017/04/21 Javascript
JS Testing Properties 判断属性是否在对象里的方法
2017/10/01 Javascript
vue.js 实现图片本地预览 裁剪 压缩 上传功能
2018/03/01 Javascript
通过一次报错详细谈谈Point事件
2018/05/17 Javascript
Vue Element UI + OSS实现上传文件功能
2019/07/31 Javascript
关于layui的下拉搜索框异步加载数据的解决方法
2019/09/28 Javascript
python缩进区别分析
2014/02/15 Python
Python导出DBF文件到Excel的方法
2015/07/25 Python
VSCode下好用的Python插件及配置
2018/04/06 Python
python 定时修改数据库的示例代码
2018/04/08 Python
python 搭建简单的http server,可直接post文件的实例
2019/01/03 Python
Python函数参数匹配模型通用规则keyword-only参数详解
2019/06/10 Python
Python求两点之间的直线距离(2种实现方法)
2019/07/07 Python
基于tensorflow for循环 while循环案例
2020/06/30 Python
详解Python直接赋值,深拷贝和浅拷贝
2020/07/09 Python
25个CSS3动画按钮和菜单教程分享
2012/10/03 HTML / CSS
Lookfantastic葡萄牙官方网站:欧洲第一大化妆品零售商
2018/03/17 全球购物
weblogic面试题
2016/03/07 面试题
丑小鸭教学反思
2014/02/03 职场文书
《真想变成大大的荷叶》教学反思
2014/04/14 职场文书
施工安全生产承诺书
2014/05/23 职场文书
基层党员对照检查材料
2014/09/24 职场文书
2015年教师节演讲稿范文
2015/03/19 职场文书
公司晚会主持词
2019/04/17 职场文书