【问题标题】:Uploading file using POST request in Node.js在 Node.js 中使用 POST 请求上传文件
【发布时间】:2014-10-10 06:41:31
【问题描述】:

我在 Node.js 中使用 POST 请求上传文件时遇到问题。我必须使用request 模块来实现这一点(没有外部 npms)。服务器需要它是包含文件数据的file 字段的多部分请求。在不使用任何外部模块的情况下,在 Node.js 中看起来很容易却很难做到。

我尝试过使用this example,但没有成功:

request.post({
  uri: url,
  method: 'POST',
  multipart: [{
    body: '<FILE_DATA>'
  }]
}, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});

【问题讨论】:

  • 你的表格有enctype="multipart/form-data"选项吗?
  • 我没有使用任何形式。是服务器请求。我正在使用套接字将文件从浏览器发送到服务器,然后我必须使用 POST 请求将该文件发送到另一台服务器。

标签: node.js multipartform-data http-post


【解决方案1】:

看起来您已经在使用request module

在这种情况下,您只需使用form feature 发布form feature

var req = request.post(url, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
var form = req.form();
form.append('file', '<FILE_DATA>', {
  filename: 'myfile.txt',
  contentType: 'text/plain'
});

但是如果你想从你的文件系统中发布一些现有的文件,那么你可以简单地将它作为一个可读流传递:

form.append('file', fs.createReadStream(filepath));

request 将自行提取所有相关元数据。

有关发布multipart/form-data 的更多信息,请参阅node-form-data modulerequest 在内部使用。

【讨论】:

  • 在学习node和request模块的时候,我很困惑为什么在调用post方法后可以修改表单。埋在request 文档中的是解释 - 形式“可以修改,直到在事件循环的下一个周期触发请求”。
  • 我在使用 form 和 form.append 时不断收到“[Error: write after end]”,有人知道为什么吗?
  • @VitorFreitas 你应该调用req.form() 并在调用request.post 后立即用所有适当的数据同步填充它。在同一个事件循环滴答期间执行此操作很重要,否则您的请求可能已经发送并且底层流关闭。
  • request 已弃用,您有替代方案吗?
  • @David got 是一个不错的选择
【解决方案2】:

request 实现的 formData 字段的一个未记录功能是能够将选项传递给它使用的 form-data 模块:

request({
  url: 'http://example.com',
  method: 'POST',
  formData: {
    'regularField': 'someValue',
    'regularFile': someFileStream,
    'customBufferFile': {
      value: fileBufferData,
      options: {
        filename: 'myfile.bin'
      }
    }
  }
}, handleResponse);

如果您需要避免调用requestObj.form() 但需要将缓冲区作为文件上传,这很有用。 form-data 模块还接受 contentType(MIME 类型)和 knownLength 选项。

This change 是在 2014 年 10 月添加的(所以在提出这个问题 2 个月后),所以现在应该可以安全使用(在 2017 年+)。这相当于requestv2.46.0 或更高版本。

【讨论】:

    【解决方案3】:

    Leonid Beschastny 的答案有效,但我还必须将 ArrayBuffer 转换为 Node 的 request 模块中使用的 Buffer。将文件上传到服务器后,我使用了与 HTML5 FileAPI 相同的格式(我使用的是 Meteor)。下面的完整代码-也许对其他人有帮助。

    function toBuffer(ab) {
      var buffer = new Buffer(ab.byteLength);
      var view = new Uint8Array(ab);
      for (var i = 0; i < buffer.length; ++i) {
        buffer[i] = view[i];
      }
      return buffer;
    }
    
    var req = request.post(url, function (err, resp, body) {
      if (err) {
        console.log('Error!');
      } else {
        console.log('URL: ' + body);
      }
    });
    var form = req.form();
    form.append('file', toBuffer(file.data), {
      filename: file.name,
      contentType: file.type
    });
    

    【讨论】:

    • 有一种更简单的方法可以将ArrayBuffer 转换为Buffer,使用内置的Bufferconstructor from an array of octets:var buffer = new Buffer(new Uint8Array(ab));
    • 你上一个函数中file.data、file.name和file.type中的“文件”是从哪里来的?我没有在其他任何地方看到该变量。
    • 我正在使用 Meteor 和社区包进行文件管理。但是,如果您使用的是纯节点,那么您可以使用文件系统函数来获取有关文件及其数据的所有信息nodejs.org/api/fs.html
    【解决方案4】:

    您还可以使用请求库中的“自定义选项”支持。此格式允许您创建多部分表单上传,但包含文件和额外表单信息(如文件名或内容类型)的组合条目。我发现一些库希望接收使用这种格式的文件上传,特别是像 multer 这样的库。

    此方法已正式记录在请求文档的表单部分 - https://github.com/request/request#forms

    //toUpload is the name of the input file: <input type="file" name="toUpload">
    
    let fileToUpload = req.file;
    
    let formData = {
        toUpload: {
          value: fs.createReadStream(path.join(__dirname, '..', '..','upload', fileToUpload.filename)),
          options: {
            filename: fileToUpload.originalname,
            contentType: fileToUpload.mimeType
          }
        }
      };
    let options = {
        url: url,
        method: 'POST',
        formData: formData
      }
    request(options, function (err, resp, body) {
        if (err)
          cb(err);
    
        if (!err && resp.statusCode == 200) {
          cb(null, body);
        }
      });
    

    【讨论】:

    • edit 回答您的问题,并添加一些关于您的代码如何工作的解释或评论。这将帮助其他用户确定您的答案是否足够有趣以供考虑。否则人们必须分析你的代码(这需要时间),甚至模糊地知道这是否是他们需要的。谢谢!
    • 5 年后有人会想要一个解释,而你不会在身边或不会打扰。这就是为什么 Fabio 要求您在回复中而不是应要求提供解释。
    【解决方案5】:

    我是这样做的:

    // Open file as a readable stream
    const fileStream = fs.createReadStream('./my-file.ext');
    
    const form = new FormData();
    // Pass file stream directly to form
    form.append('my file', fileStream, 'my-file.ext');
    

    【讨论】:

      【解决方案6】:
       const remoteReq = request({
          method: 'POST',
          uri: 'http://host.com/api/upload',
          headers: {
            'Authorization': 'Bearer ' + req.query.token,
            'Content-Type': req.headers['content-type'] || 'multipart/form-data;'
          }
        })
        req.pipe(remoteReq);
        remoteReq.pipe(res);
      

      【讨论】:

        猜你喜欢
        • 2018-06-08
        • 2018-12-16
        • 2021-08-10
        • 1970-01-01
        • 1970-01-01
        • 2021-12-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多