使用 Fetch API 和 fs.createWriteStream 将响应流式传输到文件

问题描述 投票:0回答:3

我正在创建一个 Electron 应用程序,我想将图像流式传输到文件(所以基本上是下载它)。

我想使用原生的Fetch API,因为请求模块会是一个很大的开销。

但是响应中没有管道方法,所以我不能做类似的事情

fetch('https://imageurl.jpg')
    .then(response => response.pipe(fs.createWriteStream('image.jpg')));

那么我怎样才能将

fetch
fs.createWriteStream
结合起来呢?

javascript electron fs fetch-api
3个回答
16
投票

2023 年更新

现在 Node.JS 为此目的提供了助手。查看 frank-dspeed 的回答 了解更多详情。

原答案

我成功了。我创建了一个将响应转换为可读流的函数。

const responseToReadable = response => {
    const reader = response.body.getReader();
    const rs = new Readable();
    rs._read = async () => {
        const result = await reader.read();
        if(!result.done){
            rs.push(Buffer.from(result.value));
        }else{
            rs.push(null);
            return;
        }
    };
    return rs;
};

有了它,我就能做到

fetch('https://imageurl.jpg')
    .then(response => responseToReadable(response).pipe(fs.createWriteStream('image.jpg')));

5
投票

我想今天的答案是 Nodejs 18+

node -e 'fetch("https://github.com/stealify").then(response => stream.Readable.fromWeb(response.body).pipe(fs.createWriteStream("./github.com_stealify.html")))'

在上面的示例中,我们使用 -e 标志,它告诉 nodejs 执行我们的 cli 代码,我们在这里下载一个有趣的项目页面并将其另存为 ./github.com_stealify.html 在当前工作目录中,下面的代码显示了相同的内容为了方便起见,放在 nodejs .mjs 文件中

使用 CommonJS 的 Cli 示例

node -e 'fetch("https://github.com/stealify").then(({body:s}) =>
 stream.Readable.fromWeb(s).pipe(fs.createWriteStream("./github.com_stealify.html")))'

fetch.cjs

fetch("https://github.com/stealify").then(({body:s}) => 
 require("node:stream").Readable.fromWeb(s)
  .pipe(require("node:fs").createWriteStream("./github.com_stealify.html")));

使用 ESM 的 CLI 示例

node --input-type module -e 'stream.Readable.fromWeb(
 (await fetch("https://github.com/stealify")).body)
  .pipe(fs.createWriteStream("./github.com_stealify.html"))'

fetch_tla_no_tli.mjs

(await import("node:stream")).Readable.fromWeb(
 (await fetch("https://github.com/stealify")).body).pipe(
  (await import("node:fs")).createWriteStream("./github.com_stealify.html"));

fetch.mjs

import stream from 'node:stream';
import fs from 'node:fs';
stream.Readable
  .fromWeb((await fetch("https://github.com/stealify")).body)
  .pipe(fs.createWriteStream("./github.com_stealify.html"));

参见:https://nodejs.org/api/stream.html#streamreadablefromwebreadablestream-options

更新我在处理文件时不会使用此方法

这是正确的用法,因为 fs.promises 支持与流/消费者 api 相同的所有形式的迭代器

node -e 'fetch("https://github.com/stealify").then( (res) =>
 fs.promises.writeFile("./github.com_stealify.html", res.body)))'

对于 TypeScript:

import { Readable } from "stream";
import fs from 'fs'
import { ReadableStream } from "stream/web";

fetch("https://github.com/stealify").then((res) => {
  if (res.body) {
    return Readable.fromWeb(res.body as ReadableStream<any>)
      .pipe(fs.createWriteStream("./tmp/github.com_stealify.html"))
  }
})

4
投票

Fetch 并不真正能够开箱即用地使用 Nodejs Streams,因为浏览器中的 Stream API 与 NodeJS 提供的 API 不同,即您不能将浏览器流传输到 NodeJS 流中,反之亦然。

Electron-fetch 模块似乎可以为您解决这个问题。或者你可以看看这个答案:https://stackoverflow.com/a/32545850/2016129有一种无需nodeIntegration即可下载文件的方法。

还有

needle,它是较大请求的较小替代方案,当然支持 Streams。

© www.soinside.com 2019 - 2024. All rights reserved.