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 10 Javascript
javascript函数库-集合框架
Apr 27 Javascript
js拦截alert对话框另类应用
Jan 16 Javascript
jquery配合css简单实现返回顶部效果
Sep 30 Javascript
json属性名为什么要双引号(个人猜测)
Jul 31 Javascript
javascript中的正则表达式使用指南
Mar 01 Javascript
原生JS实现的放大镜效果实例代码
Oct 15 Javascript
node.js文件上传处理示例
Oct 27 Javascript
浅析使用BootStrap TreeView插件实现灵活配置快递模板
Nov 28 Javascript
详解Vue2中组件间通信的解决全方案
Jul 28 Javascript
vue实现日历表格(element-ui)
Sep 24 Javascript
vue制作toast组件npm包示例代码
Oct 29 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 创建标签云函数代码
2010/05/26 PHP
php通过文件头检测文件类型通用代码类(zip,rar等)
2010/10/19 PHP
yii2实现分页,带搜索的分页功能示例
2017/01/07 PHP
Javascript 复制数组实现代码
2009/11/26 Javascript
利用location.hash实现跨域iframe自适应
2010/05/04 Javascript
Js 随机数产生6位数字
2010/05/13 Javascript
juqery 学习之三 选择器 层级 基本
2010/11/25 Javascript
DD_belatedPNG,IE6下PNG透明解决方案(国外)
2010/12/06 Javascript
jquery实现奇偶行赋值不同css值
2012/02/17 Javascript
GRID拖拽行的实例代码
2013/07/18 Javascript
javascript常用经典算法实例详解
2015/11/25 Javascript
angularjs ui-router中路由的二级嵌套
2017/03/10 Javascript
nodejs的路径问题的解决
2018/06/30 NodeJs
JS实现随机生成10个手机号的方法示例
2018/12/07 Javascript
vue中使用vee-validator完成表单校验方案
2019/11/01 Javascript
vue获取data数据改变前后的值方法
2019/11/07 Javascript
jQuery实现轮播图效果demo
2020/01/11 jQuery
react 不用插件实现数字滚动的效果示例
2020/04/14 Javascript
分分钟入门python语言
2018/03/20 Python
PyCharm代码整体缩进,反向缩进的方法
2018/06/25 Python
python样条插值的实现代码
2018/12/17 Python
Python学习笔记之lambda表达式用法详解
2019/08/08 Python
利用python中集合的唯一性实现去重
2020/02/11 Python
Python自动登录QQ的实现示例
2020/08/28 Python
python安装sklearn模块的方法详解
2020/11/28 Python
python集合的新增元素方法整理
2020/12/07 Python
芬兰攀岩、山地运动和户外活动用品购物网站:Bergfreunde
2016/10/06 全球购物
Belvilla德国:在线预订度假屋
2018/04/10 全球购物
德国受欢迎的旅游和休闲网站:lastminute.de
2019/09/23 全球购物
门卫岗位职责
2013/11/15 职场文书
房地产还款计划书
2014/01/10 职场文书
军校本科大学生自我评价
2014/01/14 职场文书
小学数学国培感言
2014/03/10 职场文书
领导班子在批评与自我批评座谈会上的发言
2014/09/28 职场文书
python实现简单倒计时功能
2021/04/21 Python
ubuntu安装jupyter并设置远程访问的实现
2022/03/31 Python