使用 Fetch API 和 fs.createWriteStream 对文件进行流式响应

Posted

技术标签:

【中文标题】使用 Fetch API 和 fs.createWriteStream 对文件进行流式响应【英文标题】:Stream response to file using Fetch API and fs.createWriteStream 【发布时间】:2017-11-24 04:06:52 【问题描述】:

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

我想使用本机 Fetch API,因为请求模块的开销很大。

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

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

那么我该如何组合fetchfs.createWriteStream

【问题讨论】:

【参考方案1】:

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

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

还有needle,一个更小的替代大请求,当然支持流。

【讨论】:

这不是真的。看看这里developer.mozilla.org/en-US/docs/Web/API/Streams_API/… 虽然浏览器支持流,但它们与 nodejs 的流并不真正兼容。您必须使用某种中间件来连接两者。【参考方案2】:

我让它工作了。我做了一个函数,将响应转换为可读流。

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

【讨论】:

小心!这会将文件的全部内容加载到内存中...下载 2 GB 文档时可能不理想...您可能会耗尽内存。 @KarstenDaemen 你能指出哪一行代码将它全部加载到内存中吗?我认为const result = await reader.read() 这行只读取了一个块。

以上是关于使用 Fetch API 和 fs.createWriteStream 对文件进行流式响应的主要内容,如果未能解决你的问题,请参考以下文章

使用 ReactJS 和 fetch-api 访问和显示 JSON 时遇到问题

使用像 fiddler 这样的代理和 fetch api

使用 fetch() API 返回部分视图

Morgan Logger + Express.js:写入文件并在控制台中显示

如何使用“Fetch API”在 javascript 和 c# 之间传递数据?

使用 fetch api 反应钩子