简体   繁体   English

在 Node.js 中使用 POST 请求上传文件

[英]Uploading file using POST request in Node.js

I have problem uploading file using POST request in Node.js. I have to use request module to accomplish that (no external npms).我在 Node.js 中使用 POST 请求上传文件时遇到问题。我必须使用request模块来完成(没有外部 npms)。 Server needs it to be multipart request with the file field containing file's data.服务器需要它是包含文件数据的file字段的多部分请求。 What seems to be easy it's pretty hard to do in Node.js without using any external module.在 Node.js 中,不使用任何外部模块就很难做到看似简单的事情。

I've tried using this example but without success:我试过使用这个例子但没有成功:

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

Looks like you're already using request module .看起来您已经在使用request module

in this case all you need to post multipart/form-data is to use its form feature :在这种情况下,您只需发布multipart/form-data即可使用其form功能

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'
});

but if you want to post some existing file from your file system, then you may simply pass it as a readable stream:但是如果你想从你的文件系统中发布一些现有的文件,那么你可以简单地将它作为可读流传递:

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

request will extract all related metadata by itself. request将自行提取所有相关元数据。

For more information on posting multipart/form-data see node-form-data module , which is internally used by request .有关发布multipart/form-data更多信息,请参阅node-form-data模块,该模块request内部使用。

An undocumented feature of the formData field that request implements is the ability to pass options to the form-data module it uses: request实现的formData字段的一个未记录的功能是能够将选项传递给它使用的form-data模块:

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

This is useful if you need to avoid calling requestObj.form() but need to upload a buffer as a file.如果您需要避免调用requestObj.form()但需要将缓冲区作为文件上传,这将非常有用。 The form-data module also accepts contentType (the MIME type) and knownLength options. form-data模块还接受contentType (MIME 类型)和knownLength选项。

This change was added in October 2014 (so 2 months after this question was asked), so it should be safe to use now (in 2017+). 此更改于 2014 年 10 月添加(因此在提出此问题后 2 个月),因此现在使用应该是安全的(在 2017 年以上)。 This equates to version v2.46.0 or above of request .这等同于版本v2.46.0或以上的request

Leonid Beschastny's answer works but I also had to convert ArrayBuffer to Buffer that is used in the Node's request module. Leonid Beschastny 的回答有效,但我还必须将 ArrayBuffer 转换为 Node request模块中使用的 Buffer。 After uploading file to the server I had it in the same format that comes from the HTML5 FileAPI (I'm using Meteor).将文件上传到服务器后,我使用了与 HTML5 FileAPI 相同的格式(我使用的是 Meteor)。 Full code below - maybe it will be helpful for others.下面的完整代码 - 也许对其他人有帮助。

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
});

You can also use the "custom options" support from the request library.您还可以使用请求库中的“自定义选项”支持。 This format allows you to create a multi-part form upload, but with a combined entry for both the file and extra form information, like filename or content-type.此格式允许您创建多部分表单上传,但包含文件和额外表单信息(如文件名或内容类型)的组合条目。 I have found that some libraries expect to receive file uploads using this format, specifically libraries like multer.我发现一些库希望使用这种格式接收文件上传,特别是像 multer 这样的库。

This approach is officially documented in the forms section of the request docs - https://github.com/request/request#forms这种方法正式记录在请求文档的表单部分 - 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);
    }
  });

I did it like this:我是这样做的:

// 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');
 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM