Запись потока, возвращаемого node-fetch

README содержит следующий код в качестве примера записи извлеченного файла:

fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
    .then(res => {
        const dest = fs.createWriteStream('./octocat.png');
        res.body.pipe(dest);
    });

к которому я бы присоединил еще один .then(), чтобы использовать файл, записанный на диск. на самом деле кажется, что мой код запускается до того, как файл закончит запись на диск, поэтому мне приходит в голову, что обещание, возвращаемое приведенным выше кодом, должно учитывать выдачу события «конец» в потоке. может что-то вроде этого:

fetch(url).then(res => new Promise((resolve, reject) => {
    const dest = fs.createWriteStream(fn);
    res.body.pipe(dest);
    res.body.on('end', () => resolve());
    dest.on('error', reject);
}));

но когда я пытаюсь запустить этот код, он жалуется:

TypeError: res.body.on не является функцией

что имеет смысл, учитывая, что res.body выглядит так:

{ pipe: [Function: pipe] }

то есть это вообще не поток

два вопроса: 1) как мне получить доступ к реальному стриму? 2) если у меня нет к нему доступа, как я могу узнать, когда поток чтения закрылся, чтобы я мог решить?

p.s.

и нет, я не могу получить поток от .pipe(), который возвращает undefined


person ekkis    schedule 26.03.2019    source источник


Ответы (2)


Насколько я могу судить, ваш код правильный. я побежал

const fs = require("fs");
const fetch = require("node-fetch");

fetch("https://assets-cdn.github.com/images/modules/logos_page/Octocat.png")
  .then(
    res =>
      new Promise((resolve, reject) => {
        const dest = fs.createWriteStream("./tmp.txt");
        res.body.pipe(dest);
        res.body.on("end", () => resolve("it worked"));
        dest.on("error", reject);
      })
  )
  .then(x => console.log(x));

и он работал точно так, как ожидалось, и печатал "it worked"

person m0meni    schedule 26.03.2019
comment
возможно, это связано с версией node.js... Я использую 11.5.0, и он ломается, как я указал - person ekkis; 26.03.2019
comment
@ekkis Хм, я на v11.12.0. Он сломается, даже если вы скопируете вышеперечисленное и запустите его? - person m0meni; 26.03.2019
comment
Я проверил это. это сработало. Я немного смущен, как это могло быть. посмотрю... спасибо - person ekkis; 27.03.2019
comment
Я нашел свою проблему. это был плохой макет в тестах. спасибо, что следите за этим - person ekkis; 27.03.2019
comment
есть асинхронная версия? - person stackdave; 17.12.2019
comment
Отличный ответ, спасибо; Вы знаете, как получить content-type response header из res.body? - person yPhil; 24.03.2021
comment
Привет, я пытаюсь вернуть двоичные данные, как только узел закончит их читать. Можете ли вы сказать мне, как это сделать? - person Jyotirmoy Pan; 30.07.2021

Я понял. записываемый поток автоматически закроется, когда закроется доступный для чтения. поэтому я могу подключиться к этому вместо этого:

fetch(url).then(res => new Promise((resolve, reject) => {
    const dest = fs.createWriteStream(fn);
    res.body.pipe(dest);
    dest.on('close', () => resolve());
    dest.on('error', reject);
}));
person ekkis    schedule 26.03.2019
comment
просто хотел добавить fn это имя файла в приведенном выше примере - person Colin D; 15.07.2020