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
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