FEATURED · 精选文章

Axios 请求取消机制详解:AbortController 与 CancelToken 的实现原理及实战

发布时间 / 2026/9/7 15:58:31
来源 / 创域科博编辑部
栏目 / 资讯中心
Axios 请求取消机制详解:AbortController 与 CancelToken 的实现原理及实战 Axios 请求取消机制详解AbortController 与 CancelToken 的实现原理及实战【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axiosAxios 从 v0.22.0 起同时支持基于AbortController的新一代取消方式和已废弃的CancelTokenAPI。本文以 Axios 官方取消请求文档为主体完整覆盖两种 API 的用法、取消错误的判定方式与 TypeScript 类型支持并深入 lib/cancel 目录下的源码解析取消信号在调度层与 HTTP/XHR 适配器中的真实流转路径帮助你在浏览器和 Node.js 中正确、可靠地中断在途请求并妥善处理取消引发的错误。一、AbortController推荐的取消方式从 v0.22.0 起Axios 支持使用 Web 标准的AbortController以简洁的方式取消请求。该功能在浏览器和 Node.js使用支持AbortController的版本中均可用。用法是创建一个AbortController实例并把它的signal传入请求配置的signal选项const controller new AbortController(); axios .get(/foo/bar, { signal: controller.signal, }) .then(function (response) { //... }); // 取消请求 controller.abort();这是与平台标准fetch的signal参数一致的语义因此可以直接复用浏览器原生信号、AbortSignal.timeout()或 React/Vue 组件卸载时创建的控制器无需引入 Axios 私有 API。源码中的取消检查点signal并不是直接透传给底层请求对象的孤立选项而是贯穿了请求生命周期的多个检查点。在调度层 lib/core/dispatchRequest.js 中throwIfCancellationRequested函数同时检查两种取消来源function throwIfCancellationRequested(config) { if (config.cancelToken) { config.cancelToken.throwIfRequested(); } if (config.signal config.signal.aborted) { throw new CanceledError(null, config); } }它被调用在三个关键时机请求发出前dispatchRequest.js 第 41 行若signal在请求开始前就已处于 aborted 状态直接抛出CanceledError底层适配器根本不会被执行——这正是文档中已取消状态下发起的请求会立即取消、不会尝试实际网络请求的实现来源适配器成功返回后dispatchRequest.js在transformResponse处理响应数据前再检查一次防止慢速响应的数据被继续加工适配器失败路径中dispatchRequest.js若失败原因不是取消错误仍补一次取消检查把响应错误重新归类为取消。在 Node.js 的 HTTP 适配器 lib/adapters/http.js 中信号被真正挂接到原生请求上if (config.cancelToken || config.signal) { config.cancelToken config.cancelToken.subscribe(abort); if (config.signal) { config.signal.aborted ? abort() : config.signal.addEventListener(abort, abort); } }可见 Axios 对两种取消机制做了统一归并cancelToken通过订阅subscribe接入signal通过标准的abort事件接入且都先判断是否已处于取消状态。请求结束时两者都会被解绑unsubscribe/removeEventListener见 http.js 与浏览器适配器的 xhr.js避免事件监听器泄漏。浏览器 XHR 适配器同样处理这两种信号在 lib/adapters/xhr.js 中订阅取消并在done()中清理监听。二、CancelToken已废弃但仍可用的经典 APIAxios 也保留了CancelTokenAPI 来取消请求。该 API已废弃将在下一个主版本中移除官方建议改用AbortController但对存量代码而言它仍是当前版本中功能完整的方案。方式一CancelToken.source() 工厂方法最直观的用法是CancelToken.source()工厂方法它返回{ token, cancel }对象——把token放入请求配置把cancel函数留给业务代码const CancelToken axios.CancelToken; const source CancelToken.source(); axios .get(/user/12345, { cancelToken: source.token, }) .catch(function (thrown) { if (axios.isCancel(thrown)) { console.log(Request canceled, thrown.message); } else { // 处理错误 } }); axios.post( /user/12345, { name: new name, }, { cancelToken: source.token, } ); // 取消请求message 参数可选 source.cancel(Operation canceled by the user.);对应源码在 lib/cancel/CancelToken.js 的静态方法source()它通过执行函数捕获内部的cancel函数并暴露出来返回token与cancel的配对。方式二执行函数executor模式也可以向CancelToken构造函数传入执行函数来创建令牌适合取消时机由复杂逻辑决定的场景const CancelToken axios.CancelToken; let cancel; axios.get(/user/12345, { cancelToken: new CancelToken(function executor(c) { // 执行函数接收一个 cancel 函数作为参数 cancel c; }), }); // 取消请求 cancel();构造函数对参数做了严格校验executor必须是函数否则抛出TypeError(executor must be a function.)CancelToken.js。此外注意构造函数内部是同步调用executorcancel必须在构造完成后通常是请求发出后的回调里才被赋值使用不能在构造期间直接调用。底层辅助方法subscribe / unsubscribe / toAbortSignalCancelToken还为旧版集成暴露了一些底层辅助方法用于把取消令牌桥接到其他监听体系或标准AbortSignalconst source axios.CancelToken.source(); const listener (cancel) { console.log(cancel.message); }; source.token.subscribe(listener); const signal source.token.toAbortSignal(); // 将 signal 传给接受 AbortSignal 的 API。 source.cancel(Operation canceled by the user.); source.token.unsubscribe(listener);从源码看这三个方法的实现要点CancelToken.jssubscribe(listener)若令牌已被取消this.reason存在则同步立即回调listener(this.reason)否则把监听器压入_listeners数组等待取消发生时统一触发触发后_listeners置为null防止重复派发unsubscribe(listener)从监听数组中移除指定函数toAbortSignal()内部新建一个AbortController通过subscribe把取消原因桥接为controller.abort(err)并且给返回的signal挂上了自定义的unsubscribe方法() this.unsubscribe(abort)供如 Axios 适配器composeSignals一类的组合逻辑做清理。三、取消错误CanceledError 与 isCancel被取消的请求会以axios.CanceledError拒绝reject。旧版导出axios.Cancel是axios.CanceledError的别名兼容旧代码取消错误上还带有__CANCEL__标记供axios.isCancel判断使用。这些结论均可在源码中逐一验证lib/cancel/CanceledError.jsCanceledError继承自AxiosError构造函数写入错误码AxiosError.ERR_CANCELED、name CanceledError以及关键标记this.__CANCEL__ true当 message 为空时默认使用字符串canceledlib/cancel/isCancel.jsisCancel(value)的实现就是!!(value value.__CANCEL__)即基于__CANCEL__属性做鸭子类型判断这也是为什么toAbortSignal桥接等路径必须确保最终 reject 的是带该标记的错误对象lib/axios.jsaxios.CanceledError、axios.CancelToken、axios.isCancel三个成员的挂载位置以及第 63 行axios.Cancel axios.CanceledError的别名声明。单元测试 tests/unit/cancel/canceledError.test.js 也印证了行为细节默认消息为CanceledError: canceled自定义消息原样保留且node:util/types的isNativeError能识别它为原生错误方便在通用错误处理管道中与普通Error一致对待。TypeScript 下的 isCancel 类型收窄在 TypeScript 中isCancelT, D, P()在收窄unknown错误类型时会保留响应数据、请求数据和查询参数的泛型interface SearchResponse { results: string[]; } interface RequestBody { includeArchived: boolean; } interface SearchParams { query: string; } try { await axios.get(/search); } catch (error) { if (axios.isCancelSearchResponse, RequestBody, SearchParams(error)) { error.response?.data; // SearchResponse | undefined error.config?.data; // RequestBody | undefined error.config?.params; // SearchParams | undefined } }这一能力的根源是CanceledError构造时携带了config与request参数见 CanceledError.js而AxiosError基类又把二者挂到了错误实例的config/request上因此取消错误对象本身就携带了请求上下文类型系统得以在此基础上做精确收窄。四、一个令牌取消多个请求与预取消行为你可以使用同一个取消令牌或AbortController取消多个请求。如果在 Axios 请求开始时取消令牌已处于已取消状态则请求会立即被取消不会尝试发起实际的网络请求。这一行为的底层依据在前文已说明对AbortController路径throwIfCancellationRequested在请求发出前检查config.signal.aborted直接抛出CanceledErrordispatchRequest.js对CancelToken路径token.throwIfRequested()在已取消存在reason时立即抛出该CanceledErrorCancelToken.js适配层对已取消的信号同样做了短路处理signal.aborted ? abort() : addEventListener(...)http.jssubscribe对已取消令牌也立即同步回调监听器CancelToken.js。因此批量取消的典型模式是为一批并发请求共享一个source/controller需要整体中断时调用一次cancel(message)/abort()所有在途与未发出的请求都会收到带统一 message 的CanceledError已经发出且已完成的请求不受影响。取消与超时的归并处理值得补充的是在 Node.js 适配器的流式场景下取消还会与超时错误发生交互。从 lib/adapters/http.js 的结构看abortEmitter用once(abort)统一驱动 reject流被中途断开时以CanceledError(Request stream has been aborted, config, req)拒绝http.js。浏览器端取消相关的行为另有专项测试覆盖可参见 tests/browser/cancel.browser.test.js 与 tests/browser/cancelToken.browser.test.js单元测试侧则包括 tests/unit/cancel/isCancel.test.js。五、两种 API 的选择建议维度AbortControllerCancelToken状态推荐Web/Node 标准已废弃将在下一个主版本移除配置项signal: controller.signalcancelToken: source.token触发取消controller.abort(reason?)source.cancel(message?)与平台 API 互通可直接复用原生AbortSignal需经token.toAbortSignal()桥接多请求共享共享同一controller共享同一source.token判定取消错误axios.isCancel(error)axios.isCancel(error)相同迁移路径很直接把CancelToken.source()换成new AbortController()把cancelToken: source.token换成signal: controller.signal把source.cancel(msg)换成controller.abort(msg)——错误判定代码axios.isCancel/axios.CanceledError无需改动因为两条路径最终都归并到同一个CanceledError与__CANCEL__标记上。【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻