Node.js中取消http请求

如果您在 Node.js 中发出 HTTP 请求,如果接收响应的时间过长,您很有可能想要取消它。或者你有一个稍微复杂的情况,你并行发出多个请求,如果一个请求失败,你想取消所有请求。这些听起来是合理的事情,但解决这些问题往往不那么简单。你可能会想到一个涉及 setTimeout() 的 hacky 解决方法(是的,我曾经也想过)。

幸运的是,有一个JavaScript API 提供了标准的方式来取消异步任务,例如:正在进行的 HTTP 请求,这个API就是Abort API。这个短小,但是强大的API,自2017年后被一些web浏览器支持。现在这个功能也在Node.js中支持了。让我们来看一下Abort API是什么,怎么工作的,以及我们怎么在Node.js中取消http请求。

The Abort API

 

 

 Abort API是一个javascript API, 包含了AbortController和AbortSignal,下面是他们的一个使用例子:

const controller = new AbortController();
const signal = controller.signal;

signal.addEventListener("abort", () => {
  console.log("The abort signal was triggered");
}, { once: true });

controller.abort();

当controller.abort()方法被调用了,就会设置signal的aborted属性为true。它还从 controller.signal 中的 AbortSignal 实例向已注册的处理程序列表分派 abort 事件。上面的例子中,我们为abort类型的时间注册了一个处理成功,在这里是打印日志,让我们知道abort signal 已经触发了。如果你在使用一个包或者方法,他接受一个AbortSignal作为可选参数,它将为 abort 事件附加它自己的事件处理程序。

Abort API来自于web平台,首先来自Microsoft Edge 16 ,目前被其他浏览器也支持了。

在版本15.4.0,Node.js已经稳定支持了这个Abort API。它被反向移植到 Node.js v14.17.0,但处于实验状态,如果您使用的是 Node.js v14.x 或更早版本的 Node.js,您可能需要使用 abort-controller 库(Node.js 的核心实现是在此库上基础上建模的)。

您可以在我的文章中了解不同版本的 Node.js 中对 Abort API 的支持,‘Cancel async operations with AbortController‘.

Cancelling an HTTP request with an AbortSignal

 以下代码示例需要 Node.js v16.0.0 或更高版本,因为它们使用 setTimeout() 的 promise 变种。
 
现在,让我们了解有关 Abort API 的知识,并使用它在特定时间后取消 HTTP 请求。我们将会使用promise variant of setTimeout() ,他接受一个作为Signal选项的AbortSignal实例。我们还将另一个 AbortSignal 作为选项传递给发出 HTTP 请求的函数。然后我们将使用 Promise.race() 针对每一个http请求来“race”超时。
 
首先,我们将为 Node.js 安装一个流行的 Fetch API 实现,node-fetch:
npm install node-fetch

然后我们倒入我们这个要使用的包

// example-node-fetch.mjs

import fetch from "node-fetch";

import { setTimeout } from "node:timers/promises";

我们将会从timers/promises模块中,倒入setTimeout的Promise变种,而不是全局的回调函数setTimeout。

现在我们将会创建两个AbortController实例

// example-node-fetch.mjs

const cancelRequest = new AbortController();
const cancelTimeout = new AbortController();

下面我们将会创建makeRequest方法,这个方法使用node-fetch作为http的请求。

// example-node-fetch.mjs

async function makeRequest(url) {
  try {
    const response = await fetch(url, { signal: cancelRequest.signal });
    const responseData = await response.json();

    return responseData;
  } finally {
    cancelTimeout.abort();
  }
}

 在上面的代码片段中我们需要了解两件事情

1: fetch() 方法中我们传递了一个作为signal选项的cancelRequest.signal(AbortSignal的一个实例),这个允许我们终止fetch()发出的http请求

2: 在我们的请求完成的时候,在cancelTimeout的abort controller中我们调用了abort() 

 

现在我们可以创建一个timeout() 方法,这个方法会在指定时间后抛出一个错误。

// example-node-fetch.mjs

async function timeout(delay) {
  try {
    await setTimeout(delay, undefined, { signal: cancelTimeout.signal });

    cancelRequest.abort();
  } catch (error) {
    return;
  }

  throw new Error(`Request aborted as it took longer than ${delay}ms`);
}

 

转自:https://simonplend.com/how-to-cancel-an-http-request-in-node-js/#comments

posted @ 2015-08-23 15:59  都市烟火  阅读(14114)  评论(0编辑  收藏  举报