【问题标题】:upload a file without a temporary file using request module nodejs使用请求模块nodejs上传没有临时文件的文件
【发布时间】:2016-06-30 07:59:17
【问题描述】:

我正在尝试压缩一堆文件并将其上传到远程服务器(这也是由nodejs编写并使用多方进行表单处理)

但我想要实现的是在没有临时文件的情况下做到这一点。这意味着“:创建一个 zip 存档作为流并直接通过 request 模块上传流。

所以我写了一些测试代码,首先是服务器接收上传:

var multiparty = require('multiparty');
var http = require('http');
var util = require('util');

http.createServer(function(req, res) {
  if (req.url === '/upload' && req.method === 'POST') {
    // parse a file upload
    var form = new multiparty.Form({encoding: null});
    console.log("what?");
    form.parse(req, function(err, fields, files) {
      if (err) {
        console.error(err);
      }

      res.writeHead(200, {'content-type': 'text/plain'});
      res.write('received upload:\n\n');
      res.end(util.inspect({fields: fields, files: files}));
    });

    return;
  }

  // show a file upload form
  res.writeHead(200, {'content-type': 'text/html'});
  res.end(
    '<form action="/upload" enctype="multipart/form-data" method="post">'+
    '<input type="text" name="title"><br>'+
    '<input type="file" name="upload" multiple="multiple"><br>'+
    '<input type="submit" value="Upload">'+
    '</form>'
  );
}).listen(8080);

然后我只是使用 child_process 执行zip 命令,但我没有创建临时文件,而是将存档输出到 stdout 以创建流:

/*
    upload a manually-created readable stream from string output from zip command.
*/
var exec = require('child_process').exec;
var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';

var zipCmd = 'zip -r9 - ' + dir;

var Stream = require('stream');
var request = require('request');
var fs = require('fs');
exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
    if (err) console.error(err);

    var rs = Stream.Readable({encoding: null});

    rs.push(stdout);
    rs.push(null);

    var req = request.post('http://127.0.0.1:8080/upload', function(err, httpResponse, body) {
        if (err) console.error(err);
        console.log(body);
    });
    var form = req.form();
    form.append('image', rs);

})

但我运行上传脚本后,服务器返回

{ [Error: stream ended unexpectedly] status: 400, statusCode: 400 }

似乎该可读流有问题。

为了检查该流的内容中是否存在任何损坏。我将脚本修改为使用临时文件。

/*
    first write the stream content to a temp file, then 
    upload a new stream from the temp file.
*/
var exec = require('child_process').exec;
var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';

var zipCmd = 'zip -r9 - ' + dir;

var Stream = require('stream');
var request = require('request');
var fs = require('fs');
exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
    if (err) console.error(err);

    var rs = Stream.Readable({encoding: null});

    rs.push(stdout);
    rs.push(null);


    var ws = fs.createWriteStream('/Users/drakedan/Desktop/test.zip');
    rs.pipe(ws);// create a temp file.

    rs.on('end', function(){
        var req = request.post('http://127.0.0.1:8080/upload', function(err, httpResponse, body) {
            if (err) console.error(err);
            console.log(body);
        });
        var form = req.form();
        form.append('image', fs.createReadStream('/Users/drakedan/Desktop/test.zip')); // readstream from temp file
    });

});

这一次,服务器接受文件。

received upload:

{ fields: {}, files: { image: [ [Object] ] } }

并且可以成功解压临时文件,这意味着内容没有损坏。

所以我的问题是:

处理这种情况的正确方法是什么?

fs.createReadStream 和我手动创建的可读流有什么区别。

有没有机会全程直播?

我做错了什么?

【问题讨论】:

    标签: node.js file-upload stream request zip


    【解决方案1】:

    经过大量的挖掘,我想我找到了解决问题的方法。

    stream ended unexpectedly 错误基于我的假设,主要是因为服务器端不知道流实际结束的位置。说文件的大小是未知的。我从这个blog 得到了一些提示,它改变了transfer-encoding:'chunked' 标头。在我这样做之后,服务器似乎接受了表单,不是作为上传文件,而是作为普通字段。

    这是一个进步!然后我重新访问form-datarequest 我终于找到了正确的方法。

    解决问题的方法有两种:

    1. 使用自定义表单选项构造formData,直接将stdout作为内容。给它一个正确的内容类型然后提交它,它就完成了。

      var exec = require('child_process').exec;
      var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';
      
      var zipCmd = 'zip -r9 - ' + dir;
      
      var Stream = require('stream');
      var request = require('request');
      var fs = require('fs');
      var FormData = require('form-data');
      exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
          if (err) console.error(err);
      
          var form = new FormData();
          form.append('image', stdout, {
              filename: 'upload.zip',
              contentType: 'application/zip, application/octet-stream'
          });
      
          form.submit('http://127.0.0.1:8080/upload', function(err, res) {
              if (err) throw err;
              console.log(res);
          });
      });
      

    2.使用手动创建的可读流。虽然它似乎没有必要 在这种情况下,但仍然很高兴知道。关键是定义 knownLength,否则会出现stream ended unexpectedly

    var exec = require('child_process').exec;
    var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';
    
    var zipCmd = 'zip -r9 - ' + dir;
    
    var Stream = require('stream');
    var request = require('request');
    var fs = require('fs');
    var FormData = require('form-data');
    exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
        if (err) console.error(err);
    
        var rs = Stream.Readable({encoding: null});
    
        rs.push(stdout);
        rs.push(null);
    
        var form = new FormData();
        form.append('image', rs, {
            filename: 'upload.zip',
            contentType: 'application/zip, application/octet-stream',
            knownLength: 116089 // necessary if using custom steam
        });
    
        form.submit('http://127.0.0.1:8080/upload', function(err, res) {
            if (err) throw err;
            console.log('done');
        });
    });
    

    通过了解发生了什么,我可以使用request 更改代码来完成工作。使用自定义文件选项

    var formData = {
        image: {
            value: stdout,
            options: {
                filename: 'upload.zip',
                contentType: 'application/zip, application/octet-stream'
            }
        }
    }
    
    var req = request.post({url: 'http://127.0.0.1:8080/upload', formData: formData}, function(err, httpResponse, body) {
        if (err) console.error(err);
        console.log(body);
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-11
      • 1970-01-01
      • 2017-09-02
      • 1970-01-01
      • 1970-01-01
      • 2020-11-02
      • 2019-08-16
      • 2021-06-06
      相关资源
      最近更新 更多