Home  >  Article  >  Web Front-end  >  Detailed explanation of Node layer simulation to implement multipart form file upload

Detailed explanation of Node layer simulation to implement multipart form file upload

小云云
小云云Original
2018-01-03 09:29:431880browse

Sometimes there is such a demand. Nodejs is used as a webserver to upload files from the browser to the back-end server. The Node layer only does a data transfer. If during this process, the Node webserver needs to process the data appropriately, then Then Post to the backend, then you have to simulate file upload at the Node layer. This article mainly shares with you a file upload example of Node layer simulation to implement multipart form. It has a good reference value and I hope it will be helpful to everyone. Let’s follow the editor to take a look, I hope it can help everyone.

First, upload the file through the browser. The PostData format looks like this:

Screenshot 2014-11-22 9.18.45 pm. png

As shown in the figure, each set of data is actually separated by "-----WebkitFormBoundary....", and finally ends with this separator, and this separator is completely Customizable.

Each piece of submitted data is described by Content-Disposition. If Content-Type is not specified, the default is text/plain. If it is an uploaded binary file, just specify its mime-type.

Simple encapsulation of a method to implement file upload at the Node layer:

/**
 * 上传文件
 * @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});
 });
}

The idea is like this, and the code is not complicated. What you may need to pay extra attention to is that in the response processing of http.request, response.headers may be gzip. At this time, the buffer cannot be directly converted to String. It needs to be decoded by zlib and then converted to string. The general idea is:

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 it, maybe you just need it when passing by~~~

Related recommendations:

The role of enctype="multipart/form-data" in the form form upload image form tag

php HTTP request class , supports GET, POST, Multipart/form-data

Why does the form for uploading files need to set enctype="multipart/form-data"

The above is the detailed content of Detailed explanation of Node layer simulation to implement multipart form file upload. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn