Axios 取消请求的演进:CancelToken vs. AbortController - 指南

CancelToken(早期 Axios 取消方案)

Axios 早期使用 CancelToken 来实现请求取消,其核心是一个基于 Promise 的取消机制。我之前的文章有写

随着 Fetch API 的普及,浏览器引入了 AbortController,Axios 从 v0.22.0 开始支持该方案。下面就针对最新的AbortController做分享。

1. AbortController取消请求的基本原理

Axios 使用 AbortController 来实现请求取消功能。其核心机制是:

  1. 为每个请求创建一个 AbortController 实例
  2. 将控制器的 signal 附加到请求配置中
  3. 需要取消时调用控制器的 abort() 方法

2. 代码实现解析

2.1 请求拦截器设置

request.js 中,我们设置了请求拦截器来管理请求取消:

// 存储所有活动的 AbortController
const activeRequests =
new Map(
)
;
request.interceptors.request.use((config
) =>
{
const requestId = generateRequestId(config)
;
// 取消重复请求
if (activeRequests.has(requestId)
) {
activeRequests.get(requestId).abort('取消重复请求'
)
;
}
// 创建并存储新的控制器
const controller =
new AbortController(
)
;
activeRequests.set(requestId, controller)
;
// 附加 signal 到请求
config.signal = controller.signal;
return config;
}
)
;

2.2 响应拦截器清理

请求完成后需要清理控制器

request.interceptors.response.use((response
) =>
{
const requestId = generateRequestId(response.config)
;
activeRequests.delete(requestId)
;
// 清理控制器
return response;
}
, (error
) =>
{
// 错误处理
}
)
;

2.3 生成唯一请求ID

为了正确识别和取消特定请求,我们需要为每个请求生成唯一ID:

export
function generateRequestId(config
) {
const params = JSON.stringify(config.params || {
}
)
;
const data = JSON.stringify(config.data || {
}
)
;
return `${config.url
}-${config.method.toLowerCase(
)
}-${params
}-${data
}`
;
}

2.4 手动取消请求

提供手动取消请求的接口:

export
function cancelRequest(requestId
) {
if (activeRequests.has(requestId)
) {
activeRequests.get(requestId).abort('用户手动取消'
)
;
activeRequests.delete(requestId)
;
}
}

3. 实际应用示例

3.1 流式请求中的取消

aiAgent.js 中,我们实现了流式请求的处理和取消:

export
function qwenTalk(data, onProgress
) {
const config = {
url: '/api/chat'
,
method: 'POST'
,
data,
responseType: 'text'
}
;
currentRequestConfig = config;
// 重置状态
buffer = ''
;
lastPosition = 0
;
return request({
...config,
onDownloadProgress: (progressEvent
) =>
{
// 处理流数据
}
,
}
)
}
// 取消当前请求
export
function cancelQwenTalk(
) {
if (currentRequestConfig) {
const requestId = generateRequestId(currentRequestConfig)
;
cancelRequest(requestId)
;
currentRequestConfig =
null
;
}
}

3.2 使用示例

// 发起请求
const requestPromise = qwenTalk({
message: 'Hello'
}
, (data
) =>
{
console.log('收到数据:'
, data)
;
}
)
;
// 取消请求
cancelQwenTalk(
)
;

4. 关键点总结

  1. 唯一请求标识:通过 URL、方法、参数和数据生成唯一ID,确保能准确识别请求
  2. 控制器管理:使用 Map 存储所有活动的 AbortController
  3. 自动取消:在请求拦截器中自动取消重复请求
  4. 手动取消:提供接口让开发者可以手动取消特定请求
  5. 资源清理:请求完成后及时清理控制器,避免内存泄漏
  6. 流式处理:对于流式请求,需要额外管理状态(如 buffer 和 position)

5. 最佳实践

  1. 对于耗时请求(如大文件上传/下载、流式响应)一定要实现取消功能
  2. 页面/组件卸载时取消所有未完成的请求
  3. 用户导航离开时考虑取消不必要的请求
  4. 对于表单提交等场景,可以防止重复提交

6. 注意事项

  1. 取消请求后,Axios 会抛出 CancelError,需要适当处理
  2. 确保请求ID生成逻辑覆盖所有可能影响请求唯一性的因素
  3. 在单页应用中,组件卸载时要清理相关请求
posted on 2025-07-06 14:32  ljbguanli  阅读(43)  评论(0)    收藏  举报