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 相关文章推荐
srcElement表格样式
Sep 03 Javascript
基于jquery的一行代码轻松实现拖动效果
Dec 28 Javascript
Jquery之美中不足小结
Feb 16 Javascript
jquery 延迟执行实例介绍
Aug 20 Javascript
文本框(input)获取焦点(onfocus)时样式改变的示例代码
Jan 10 Javascript
js获取及判断键盘按键的方法
Dec 01 Javascript
简介EasyUI datagrid editor combogrid搜索框的实现
Apr 01 Javascript
jQuery 判断是否包含在数组中Array[]的方法
Aug 03 Javascript
Javascript实现一个简单的输入关键字添加标签效果实例
Jun 01 Javascript
JavaScript实现删除数组重复元素的5种常用高效算法总结
Jan 18 Javascript
Vue2.0 实现移动端图片上传功能
May 30 Javascript
javascript设计模式 ? 组合模式原理与应用实例分析
Apr 14 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
一个捕获函数输出的函数
2007/02/14 PHP
php用正则表达式匹配中文实例详解
2013/11/06 PHP
php遍历解析xml字符串的方法
2016/05/05 PHP
php防止表单重复提交实例讲解
2019/02/11 PHP
js树形控件脚本代码
2008/07/24 Javascript
Ajax请求在数据量大的时候出现超时的解决方法
2014/02/27 Javascript
JS删除字符串中重复字符方法
2014/03/09 Javascript
通过$(this)使用jQuery包装后的方法或属性
2014/05/18 Javascript
jQuery simplePage+AJAX plus分页插件用法实例
2016/02/17 Javascript
微信小程序 图片边框解决方法
2017/01/16 Javascript
JS创建Tag标签的方法详解
2017/06/09 Javascript
详解node服务器中打开html文件的两种方法
2017/09/18 Javascript
AngularJS动态添加数据并删除的实例
2018/02/27 Javascript
关于vue的语法规则检测报错问题的解决
2018/05/21 Javascript
Vue代码整洁之去重方法整理
2019/08/06 Javascript
微信小程序swiper禁止用户手动滑动代码实例
2019/08/23 Javascript
Python使用MYSQLDB实现从数据库中导出XML文件的方法
2015/05/11 Python
深入解析Python中的lambda表达式的用法
2015/08/28 Python
基于Python如何使用AIML搭建聊天机器人
2016/01/27 Python
python3解析库BeautifulSoup4的安装配置与基本用法
2018/06/26 Python
将pandas.dataframe的数据写入到文件中的方法
2018/12/07 Python
利用selenium爬虫抓取数据的基础教程
2019/06/10 Python
英国家喻户晓的高街品牌:River Island
2017/11/28 全球购物
Linux面试题LINUX系统类
2014/11/19 面试题
自荐信的禁忌和要点
2013/10/15 职场文书
省三好学生申请材料
2014/01/22 职场文书
护理专科毕业自荐信范文
2014/04/21 职场文书
电焊工岗位工作职责
2014/07/09 职场文书
小学师德师风演讲稿
2014/09/02 职场文书
倡议书作文
2015/01/19 职场文书
工厂采购员岗位职责
2015/04/07 职场文书
客户经理岗位职责大全
2015/04/09 职场文书
2015中学教学工作总结
2015/07/22 职场文书
宣传部部长竞选稿
2015/11/21 职场文书
关于springboot 配置date字段返回时间戳的问题
2021/07/25 Java/Android
详解Vue项目的打包方式(生成dist文件)
2022/01/18 Vue.js