Как отправить файл в запросе node-fetch или Node?

Как мне прикрепить файл в POST-запросе Node или Node Fetch? Я пытаюсь вызвать API, который будет импортировать файл CSV или XLS. Возможно ли это с помощью Node или Node Fetch?

Ответ 1

README.md говорит:

Используйте собственный поток для тела, как для запроса, так и для ответа.

И источники указывают, что он поддерживает несколько типов, например Stream, Buffer, Blob... и также попытается coerce как String для других типов.

Ниже фрагмента показаны 3 примера, все работают с v1.7.1 или 2.0.0-alpha5 (см. также другой пример далее с FormData):

let fetch = require('node-fetch');
let fs = require('fs');

const stats = fs.statSync("foo.txt");
const fileSizeInBytes = stats.size;

// You can pass any of the 3 objects below as body
let readStream = fs.createReadStream('foo.txt');
//var stringContent = fs.readFileSync('foo.txt', 'utf8');
//var bufferContent = fs.readFileSync('foo.txt');

fetch('http://httpbin.org/post', {
    method: 'POST',
    headers: {
        "Content-length": fileSizeInBytes
    },
    body: readStream // Here, stringContent or bufferContent would also work
})
.then(function(res) {
    return res.json();
}).then(function(json) {
    console.log(json);
});

Вот foo.txt:

hello world!
how do you do?

Примечание. http://httpbin.org/post отвечает с помощью JSON, который содержит детали отправки запроса.

Результат:

{
  "args": {}, 
  "data": "hello world!\nhow do you do?\n", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip,deflate", 
    "Connection": "close", 
    "Content-Length": "28", 
    "Host": "httpbin.org", 
    "User-Agent": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
  }, 
  "json": null, 
  "origin": "86.247.18.156", 
  "url": "http://httpbin.org/post"
}

Если вам нужно отправить файл как часть формы с большим количеством параметров, вы можете попробовать:

  • npm install form-data
  • передать объект FormData как тело (FormDataявляется видом Stream, через CombinedStream библиотека)
  • не пропускайте header в параметрах (в отличие от приведенных выше примеров)

а затем это работает:

const formData = new FormData();
formData.append('file', fs.createReadStream('foo.txt'));
formData.append('blah', 42);
fetch('http://httpbin.org/post', {
    method: 'POST',
    body: formData
})

Результат (просто показывая, что отправлено):

----------------------------802616704485543852140629
Content-Disposition: form-data; name="file"; filename="foo.txt"
Content-Type: text/plain

hello world!
how do you do?

----------------------------802616704485543852140629
Content-Disposition: form-data; name="blah"

42
----------------------------802616704485543852140629--

Ответ 2

Я искал, как использовать node-fetch для загрузки файлов через multipart/form-data, и их документы GitHub фактически показывают, как это сделать. Ниже приведен модифицированный пример, показывающий, как прикрепить буфер к FormData и загрузить его.

const FormData = require('form-data');     
const form = new FormData();

const buffer = // e.g. 'fs.readFileSync('./fileLocation');
const fileName = 'test.txt';

form.append('file', buffer, {
  contentType: 'text/plain',
  name: 'file',
  filename: fileName,
});

fetch('https://httpbin.org/post', { method: 'POST', body: form })
    .then(res => res.json())
    .then(json => console.log(json));

Делюсь этим с кем-то еще, кто гуглил "node-fetch upload file multipart", как я.

Ответ 3

Это экспресс-сервер, который передает локальный файл в ответ.

var fs = require('fs');
var express = require('express')();

express.get('/',function(req,res){
  var readStream = fs.createReadStream('./package.json');
  readStream.pipe(res);
})
express.listen(2000);

Ответ 4

Есть одна вещь, чтобы добавить к Hugues M. ответ. Загрузка файла с помощью FormData не поддерживается node-fetch. Вместо этого вам нужно использовать другие библиотеки, такие как request или request-promise. Ниже приведен фрагмент кода для загрузки файла с использованием библиотеки request-promise. resolveWithFullResponse дает необработанный ответ. Без этого обещание возвращает только тело ответа.

let rp = require('request-promise')    

var formData = {
    file: fs.createReadStream('foo.txt'),
}

let options = {
    uri:'http://httpbin.org/post',
    formData: formData,
    resolveWithFullResponse: true
}

rp.post(options).then((response) => {
    // handle response here 
})