最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Node層模擬實(shí)現(xiàn)multipart表單的文件上傳示例

 更新時(shí)間:2018年01月02日 09:58:02   作者:itKingOne  
下面小編就為大家分享一篇Node層模擬實(shí)現(xiàn)multipart表單的文件上傳示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

有時(shí)候就是有這樣的需求,Nodejs做webserver,從瀏覽器端上傳文件到后端服務(wù)器,Node層只是做一個(gè)數(shù)據(jù)中轉(zhuǎn),如果在這個(gè)過(guò)程中,Node webserver需要對(duì)數(shù)據(jù)進(jìn)行適當(dāng)加工,然后再Post到后端,那么就得在Node層模擬文件上傳了。

首先,通過(guò)瀏覽器上傳文件,PostData格式是長(zhǎng)著個(gè)樣子的:

屏幕快照 2014-11-22 下午9.18.45.png

如圖,每一組數(shù)據(jù)其實(shí)就是用“-----WebkitFormBoundary.....”分隔開(kāi)的,最后再用這個(gè)分隔符結(jié)束,而且,這個(gè)分隔符完全是可自定義的。

每一段提交數(shù)據(jù),則通過(guò)Content-Disposition來(lái)描述,未指定Content-Type,則默認(rèn)text/plain,如果是上傳的二進(jìn)制文件,指定其mime-type即可。

簡(jiǎn)單封裝一個(gè)方法,實(shí)現(xiàn)Node層的文件上傳:

/**
 * 上傳文件
 * @param files  經(jīng)過(guò)formidable處理過(guò)的文件
 * @param req  httpRequest對(duì)象
 * @param postData 額外提交的數(shù)據(jù)
 */
function uploadFile(files, req, postData) {
 var boundaryKey = Math.random().toString(16);
 var endData = '\r\n----' + boundaryKey + '--';
 var filesLength = 0, content;

 // 初始數(shù)據(jù),把post過(guò)來(lái)的數(shù)據(jù)都攜帶上去
 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);

 // 組裝數(shù)據(jù)
 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));

 // 執(zhí)行上傳
 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 () {
   // 上傳成功一個(gè)文件之后,把臨時(shí)文件刪了
   fs.unlink(files[key].path);
   uploadedCount++;
   if (uploadedCount == fileNum) {
    // 如果已經(jīng)是最后一個(gè)文件,那就正常結(jié)束
    req.end(endData);
   }
  });
  fileStream.pipe(req, {end: false});
 });
}

思路就這樣,代碼也不復(fù)雜,可能額外需要注意的是,在http.request的response處理中,response.headers可能是gzip的,這個(gè)時(shí)候buffer不能直接toString,需要通過(guò)zlib解碼再轉(zhuǎn)換為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) {
  // 接口返回?cái)?shù)據(jù)格式異常,解析失敗
  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 的數(shù)據(jù),需要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一下,也許你路過(guò)正好需要~~~

以上這篇Node層模擬實(shí)現(xiàn)multipart表單的文件上傳示例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

宜君县| 保山市| 许昌市| 和顺县| 修水县| 吉木萨尔县| 怀仁县| 六枝特区| 金乡县| 天门市| 东山县| 平泉县| 阳曲县| 韩城市| 汨罗市| 江源县| 若羌县| 武穴市| 左权县| 启东市| 岚皋县| 永泰县| 阿勒泰市| 朔州市| 甘泉县| 嵊州市| 宜黄县| 广南县| 佛坪县| 江阴市| 囊谦县| 涡阳县| 晋江市| 三门县| 宣威市| 大邑县| 富民县| 璧山县| 海原县| 府谷县| 石屏县|