返回博客
指南
索林-加布里埃尔·马里卡2022年12月7日阅读时间:10分钟

学习如何使用 Node-Fetch NPM 在 Node.js 中发出 HTTP 请求

学习如何使用 Node-Fetch NPM 在 Node.js 中发出 HTTP 请求

Node-Fetch API 简介

在开始介绍 Node-Fetch API 之前,我必须先简单介绍一下什么是 HTTP 请求。HTTP 请求的目的是从互联网上的所有 url 获取信息。HTTP 请求的一个简单例子就是访问网站。

很久以前,HTTP 请求是使用 XMLHttpRequest 或 XHR 对象完成的,而现在所有的现代浏览器都支持 javascript 的 Fetch API。这使得程序员可以使用更简单、更干净的语法来完成请求。然而,Node.JS 服务器端语言长期以来一直缺少获取 API,这就为其他定制软件包提供了实现该功能的空间,例如 Axios、GOT 和许多其他软件包:Axios、GOT 等。

Node-Fetch 等同于 javascript 中的 Fetch API,现在终于可以在 Node.JS 中使用了。

使用 Node-Fetch API 的先决条件

首先,由于这是 Node.JS 教程,您当然需要安装 Node.JS。如果您还没有安装 Node.JS,可以从以下链接下载并安装。

Node.js 直到 17.5 版本才开始提供对 Fetch API 的实验性支持。因此,您需要至少使用 Node 17.5 版本。此外,您还需要使用 –experimental-f参数。

如果您的 Node.JS 版本较低,要跳转到最新版本,可以使用 n 软件包。N 是一个 npmjs 软件包,其唯一目的是允许您在 node 和 npm 版本之间切换。要安装它并切换到最新版本,请按以下步骤操作:

npm install -g n
n 最新版本

test 命令将安装最新版本的 Node.js。要验证您的 Node.js 版本,只需运行以下命令:

node -version

如何使用 Node-Fetch

在任何编程语言中进行 HTTP 请求都是异步操作,因为接收请求的响应需要时间。关于如何使用异步操作,有两种方法。一种是等待响应,然后继续编写代码;另一种是并行运行代码。

Node-Fetch 支持同步和异步函数调用。

Node-Fetch 中的 GET 请求

要进行简单的获取请求并从响应中提取正文,可以使用下面的代码:

fetch('https://www.webscrapingapi.com/')

    .then((response) => response.text())

    .then((body) => {

        console.log(body);

    });

要运行此代码,请将其保存为名为 node-fetch-example.js 的文件,然后在同一文件夹中使用以下命令运行: node --experimental-fetch node-fetch-example.js。请注意,运行时会出现一条警告,提示“Fetch API 是一项实验性功能”。这是正常的,因为在撰写本文时,这确实是一项实验性功能。

VS Code 展示了一个 Fetch 请求示例,终端输出提示警告称 Fetch API 处于实验阶段

上面的代码段在继续执行之前不会等待请求完成。这意味着该代码段下方的任何代码都会立即开始执行,而不会等待 fetch 操作完成。例如,如果你添加一个 console.log("Something”);,执行脚本时,输出结果将如下所示:

VS Code 终端输出显示了控制台日志结果以及一条关于实验性 Fetch API 的警告

为了进一步解释上面的代码,您可能会注意到我们使用了两次“then”函数。第一个“then”会在收到 HTTP 请求的响应时执行,其作用是将该响应与 response.tetext() 方法(该方法返回响应正文)的内容进行映射。但是, response.text() 方法本身也是异步的,因此我们需要在第二个“then”中等待其响应,其中 body 即为 response.text() 承诺的结果。

您也可以像下面的示例一样,使用 await 调用获取 API:

(async () => {

    const response = await fetch('https://webscrapingapi.com');

    const body = await response.text();

    console.log(body);

})();

这就更好地解释了 fetch API 的工作原理,以及需要等待的承诺是什么。在本文中,我们将进一步使用带有 await 的 fetch api,因为这可以让我们的代码语法更简洁。

向请求发送标题

发送请求时需要的另一个功能是设置请求的头信息。为此,您可以在获取 API 的第二个参数中添加头信息,如下所示:

(async () => {

    const response = await fetch('http://httpbin.org/headers', {

        headers: {

            'my-custom-header': 'my-header-value'

        }

    });

    const body = await response.text();

    console.log(body);

})();

除了标头,您还可以在获取 API 的第二个参数中发送更多选项。要查看所有选项,请查阅获取 API(客户端使用的API的文档

Node-Fetch 中的 POST 请求

获取 API 的另一个重要选项是方法选项。它指定了用于 HTTP 请求的方法。你可以使用 5 种方法:GET、POST、PUT、PATCH 和 DELETE,但其中前两种最常用(GET 和 POST)。默认情况下,如果没有指定方法,Node-Fetch 将使用 GET。

要使用 Node-Fetch 发送 POST 请求,可以使用以下代码片段:

(async () => {

    const response = await fetch('http://httpbin.org/post', {

        method: 'POST',

        body: JSON.stringify({

            'key': 'value'

        })

    });

    const body = await response.text();

    console.log(body);

})();
使用 JSON 发送 POST 请求的代码示例,以及显示 JSON 响应内容的终端输出

您可能会注意到,我们使用 JSON.stringify 发送请求的正文。这是因为 fetch api 会以字符串的形式发送正文,而不是像其他软件包(如 axios)那样以对象的形式发送。

获取 API 还涵盖所有其他请求方法。

节点获取中的错误处理

处理 HTTP 请求时的错误是必须的,因为您永远无法指望第三方服务始终可用。作为最佳实践,您应始终处理错误,以防止您的应用程序或脚本与您所请求的 URL 一起宕机。

node-fetch 中的错误处理可以通过在代码周围使用简单的 try catch 语法来完成。下面是一个示例,说明如何在使用 await 时做到这一点:

(async () => {

    try {

        const response = await fetch('[INVALID_URL]');

        const responseBody = await response.text();

    } catch (error) {

        console.log(error.message);

    }

})();

如果你更喜欢使用 fetch 而不使用 await,那么你可以在代码中添加一个 catch,就像这样:

fetch('[INVALID_URL]')

    .then((response) => response.text())

    .then((body) => {

        console.log(body);

    })

    .catch((error) => {

        console.log(error.message);

    });

节点获取的使用案例

提出 HTTP 请求在很多方面都很有用,因为它可以从不同的服务中获取新信息,并以非常优雅和简单的方式提取数据。在下面的段落中,我们将探讨一些这方面的用例。

使用 Node-Fetch 获取 API 请求

特写照片:有人正在白板上书写“USE APIs”,并有一支箭头指向该文字

编程时,您可能经常需要使用 API。原因是您可能需要从不同的后端来源获取特定数据,然后对其进行处理或更新。一个很好的例子是,有 4 个端点的 API 可以让您从另一个服务器在后端数据库中创建、读取、更新和删除用户(CRUD 操作)。

通常情况下,这样的应用程序接口需要进行身份验证,以防止未经授权的来源使用它,并更改数据使其对自己有利。HTTP 请求有许多认证方法。其中最常见的是使用 API 密钥,API 提供商会给你一个只有你知道的密钥,API 的端点只有在发送正确的密钥时才能工作。

另一种保护应用程序接口的方法是基本认证(Basic Authentication)。这意味着,要访问 API,您需要发送一个包含格式为 "username:password "的 base64 编码字符串的头。下面举例说明如何在 POST 请求中使用基本身份验证:

(async () => {

    const response = await fetch('http://httpbin.org/post', {

        method: 'POST',

        headers: {

            "Authorization": `Basic ${btoa('login:password')}`

        },

        body: JSON.stringify({

            'key': 'value'

        })

    });

    const body = await response.text();

    console.log(body);

})();

使用 Node-Fetch 进行网络抓取

网络抓取(Web Scraping)是一种从网站获取内容并对其进行解析的方法,这样您只需保留所需的数据,并可随意使用。cheerio 是一个很好的 npmjs 库,可以让数据解析变得更容易。通过该库,您可以像使用 javascript 或 jquery 一样,查询从 fetch api 获取的静态 HTML。

下面是一个如何使用获取 API 和 cheerio 获取页面标题的示例:

const cheerio = require("cheerio");

(async () => {

    const response = await fetch('https://www.webscrapingapi.com/');

    const responseBody = await response.text();

    const $ = cheerio.load(responseBody);

    console.log($('title').first().text());

})();

上面的示例应该返回 "WebScrapingAPI | All-In-One Scraping API",因为这是页面的标题(写在浏览器窗口顶部的文字)。细分一下,我们使用 fetch 从https://www.webscrapingapi.com/ 获取 HTML 页面源代码,然后使用 cheerio 解析这些内容。要了解有关 cheerio 的更多信息,请点击此处查看他们的文档 

从其他网站抓取信息在很多方面都很有用。例如,可以利用抓取的信息为机器学习模型创建一个训练数据集,或者创建一个价格比较工具,从多个来源提取数据,然后进行比较。

虽然上面的示例运行良好,但当涉及到刮擦时,fetch api 并不总是最佳选择。这是因为现在的网站都通过 javascript 显示内容,并使用验证码或其他方法来防止数据被搜刮。fetch API 的工作原理是通过简单的 CURL 连接到给定的 url,然后检索页面加载时显示的静态内容,完全不需要任何 javascript 渲染。

要在执行页面上的 javascript 代码的同时刮取数据,您可能需要研究一下 puppeteer 等替代方案,如本文有关高级刮取的描述。不过,如果你不想这么麻烦,可以使用 WebScrapingAPI,它是专门为这项任务设计的 API,可以解决所有这些问题(包括反机器人检测),而且还提供免费试用版,包含所有功能。 

摘要

总而言之,好消息是人们期待已久的获取 api 终于可以在 node.js 中使用了,尽管目前它还只是处于实验功能阶段(撰写本文时)。虽然以前也可以在 node.js 中进行请求,但唯一的方法是通过 XMLHttpRequest/XHR 对象或 Axios 或 GOT 等众多软件包。

这一更改将使客户端 javascript 和服务器端 nodejs 更加相似,因为所有现代浏览器都已在客户端 javascript 中提供并支持这一功能。

进行 HTTP 请求在很多方面都很有用,例如使用 API 或从网站上抓取数据。虽然其他 npm 软件包仍是一种选择,并将继续用于传统项目,但使用 fetch 是未来的最佳解决方案。这将提高 nodejs 代码的可读性,并使从前端到后端的切换变得更加容易。

关于作者
索林-加布里埃尔·马里卡,WebScrapingAPI 全栈开发工程师
索林-加布里埃尔·马里卡全栈开发工程师

索林·马里卡(Sorin Marica)是 WebScrapingAPI 的全栈及 DevOps 工程师,负责开发产品功能并维护确保平台平稳运行的基础设施。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网页数据。