【问题标题】:How to download files with node-fetch如何使用 node-fetch 下载文件
【发布时间】:2021-12-28 23:42:13
【问题描述】:

我需要帮助在 nodejs 中实现文件下载器。

所以我需要从服务器下载超过 25'000 个文件。我正在使用node-fetch,但我并不完全知道如何实现这一点。我尝试使用Promise.allSettled(),但我还需要一种方法来限制对服务器的并发请求数量,否则我会受到速率限制。

这是我目前的代码:

const fetch = require('node-fetch')

async function main () {
  const urls = [
    'https://www.example.com/foo.png',
    'https://www.example.com/bar.gif',
    'https://www.example.com/baz.jpg',
    ... many more (~25k)
  ]

  // how to save each file on the machine with same file name and extension?
  // how to limit the amount of concurrent requests to the server?
  const files = await Promise.allSettled(
    urls.map((url) => fetch(url))
  )
}

main()

所以我的问题是:

  • 如何限制对服务器的并发请求数量?可以使用带有node-fetch 的自定义https 代理并将maxSockets 设置为10 来解决这个问题吗?
  • 如何检查该文件是否存在于服务器上,如果存在则以相同的文件名和扩展名将其下载到我的计算机上?

如果有人可以展示一个小示例代码,我将如何实现此类功能,那将非常有帮助。

提前致谢。

【问题讨论】:

    标签: node.js download fetch node-fetch


    【解决方案1】:

    要控制同时运行的请求数量,您可以使用以下三个选项中的任何一个:

    mapConcurrent() herepMap() here:这些可以让你迭代一个数组,向主机发送请求,但是管理事情,以便你在决定的同时只有 N 个请求在运行N的值是多少。

    rateLimitMap()here:让我们来管理每秒发送的请求数。

    是否可以使用带有 node-fetch 的自定义 https 代理并将 maxSockets 设置为 10 来解决这个问题?

    我不知道有任何使用自定义 https 代理的解决方案。

    如何检查服务器上是否存在该文件,如果存在则以相同的文件名和扩展名将其下载到我的机器上?

    您不能直接访问远程 http 服务器的文件系统。因此,您所能做的就是对特定资源(url)发出 http 请求,并检查 http 响应以查看它是否返回了数据或返回了某种 http 错误,例如 404。

    至于文件名和扩展名,这完全取决于您是否已经知道要请求什么并且服务器是否支持将其作为 URL 的一部分,或者服务器是否在 http 标头中向您返回该信息。如果您请求特定的文件名和扩展名,那么您只需创建一个具有该名称和扩展名的文件,并将 http 响应数据保存到本地驱动器上的该文件。

    至于编码示例,node-fetch() 的文档在此处显示了使用流将数据下载到文件的示例:https://www.npmjs.com/package/node-fetch#streams

    import {createWriteStream} from 'fs';
    import {pipeline} from 'stream';
    import {promisify} from 'util'
    import fetch from 'node-fetch';
    
    const streamPipeline = promisify(pipeline);
    
    const url='https://github.githubassets.com/images/modules/logos_page/Octocat.png';
    const response = await fetch(url);
    
    if (!response.ok) throw new Error(`unexpected response ${response.statusText}`);
    
    await streamPipeline(response.body, createWriteStream('./octocat.png'));
    

    就我个人而言,我不会使用node-fetch,因为它的设计中心是模仿 node 的浏览器实现,这不像为 nodejs 明确构建的类似库那样友好的 API 设计。我使用got(),还有其他几个不错的库列出here。您可以选择自己喜欢的。

    这是一个使用got() 库的code example

    import {promisify} from 'node:util';
    import stream from 'node:stream';
    import fs from 'node:fs';
    import got from 'got';
    
    const pipeline = promisify(stream.pipeline);
    
    await pipeline(
        got.stream('https://sindresorhus.com'),
        fs.createWriteStream('index.html')
    );
    

    【讨论】:

    • 好的,我明白了,但是你会如何同时处理多个并发请求呢?您只展示了 1 个要下载的特定 url 的示例,但我如何将其扩展到 ~25k url?当下载失败或成功时,我如何console.log 发送消息?
    • @magic88 - 您可以将此代码放入async 函数中并在循环中调用它N 次。如果您使用数组来收集循环中创建的 Promise,那么您可以通过 Promise.all()Promise.allSettled() 判断它们何时全部完成。
    猜你喜欢
    • 1970-01-01
    • 2019-11-23
    • 2016-10-03
    • 2022-01-26
    • 2017-01-12
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 2022-12-18
    相关资源
    最近更新 更多