Axios 请求取消机制完全教程(含重复请求处理)

🌐 Axios 请求取消机制完全教程(含重复请求处理)

适合 Vue / React 项目 Axios 封装使用,含原理讲解、实战演示与最佳实践。
📌 记得收藏、点赞、关注,持续复习不迷路!


📖 目录

  1. 前言
  2. 核心目标
  3. 请求唯一标识 key 生成
  4. Axios 取消请求的三种角色
  5. CancelToken 原理详解
  6. 可选链 ?. 函数调用解读
  7. 完整封装示例
  8. 常见问题解答

🧠 前言

在现代前端中,同一个接口短时间被多次调用可能会导致:

  • 后端压力加剧
  • 前端响应错乱
  • 表单重复提交
  • 用户体验下降

Axios 提供了 CancelToken 机制来主动取消 HTTP 请求。通过配合 Map 管理 cancel 函数,可以实现在请求发起前自动取消上一次相同请求。


🎯 核心目标

我们希望实现以下功能:

  • 同一接口重复请求时自动取消前一个
  • 请求完成后自动清理内存
  • 能判断错误是否由取消引起
  • 可复用的 Axios 封装逻辑

🧩 请求唯一标识 key 生成

function getRequestKey(config: AxiosRequestConfig): string {
  const { method, url, params, data } = config
  return [method, url, JSON.stringify(params), JSON.stringify(data)].join('&')
}

用于为每个请求生成唯一字符串表示,作为 Map 的 key,防止重复。


🧩 Axios 取消请求的三种角色

1. cancelToken: CancelToken

这是挂在请求 config 上的控制对象,Axios 内部会监听它的状态来判断是否中止请求

2. cancel: (message) => void

你主动调用这个函数,就会触发取消机制,Axios 自动终止请求。

3. axios.isCancel(error)

这是用于在 catch 中判断请求是否是**“被取消”导致的失败**。

axios.isCancel(error) // true 表示是取消请求导致的错误

🔍 CancelToken 原理详解

✅ 方式一:底层写法

config.cancelToken = new axios.CancelToken((cancel) => {
  pendingRequestMap.set(requestKey, cancel)
})
  • CancelToken 接收一个执行器函数,提供 cancel 参数。
  • 你把 cancel 函数保存进 Map,后面可以调用来取消。

✅ 方式二:推荐写法(语法糖)

const source = axios.CancelToken.source()
config.cancelToken = source.token
pendingRequestMap.set(requestKey, source.cancel)
  • source.token:绑定到请求,Axios 内部监听
  • source.cancel():主动触发取消

💡 可选链 ?. 函数调用解读

pendingRequestMap.get(requestKey)?.('取消重复请求')

等价于:

const cancel = pendingRequestMap.get(requestKey)
if (cancel) cancel('取消重复请求')

作用:

  • 如果 cancel 存在,就调用它
  • 如果为 undefined,不报错、直接跳过

🧪 完整封装示例

import axios, { AxiosRequestConfig, Canceler } from 'axios'

const pendingRequestMap = new Map<string, Canceler>()

function getRequestKey(config: AxiosRequestConfig): string {
  return [config.method, config.url, JSON.stringify(config.params), JSON.stringify(config.data)].join('&')
}

function addPendingRequest(config: AxiosRequestConfig) {
  const requestKey = getRequestKey(config)
  if (pendingRequestMap.has(requestKey)) {
    pendingRequestMap.get(requestKey)?.('取消重复请求')
  }
  const source = axios.CancelToken.source()
  config.cancelToken = source.token
  pendingRequestMap.set(requestKey, source.cancel)
}

function removePendingRequest(config: AxiosRequestConfig) {
  const requestKey = getRequestKey(config)
  pendingRequestMap.delete(requestKey)
}

const service = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 15000,
  headers: { 'Content-Type': 'application/json' },
})

service.interceptors.request.use((config) => {
  removePendingRequest(config)
  addPendingRequest(config)
  return config
})

service.interceptors.response.use(
  (response) => {
    removePendingRequest(response.config)
    return response.data
  },
  (error) => {
    if (axios.isCancel(error)) {
      console.warn('请求被取消:', error.message)
      return Promise.reject({ canceled: true })
    }
    return Promise.reject(error)
  }
)

export default service

❓ 常见问题解答

✅ Q1:cancelToken 没看到我用它,它有什么用?

虽然你没主动用它,但Axios 内部监听了它的 promise,一旦你调用了 cancel,它就会中止请求。


✅ Q2:pendingRequestMap 会不会越来越大?

不会。每次请求完成后,拦截器都会调用 removePendingRequest,及时移除对应 key,防止内存泄漏。


✅ Q3:被取消的是“发出去的请求”吗?后端会知道吗?

  • 是的,是已经发出的请求(浏览器层面被中断)。
  • 后端收到请求就已经开始处理,不一定能中断逻辑,除非后端专门监听连接断开(一般不会)。

✅ Q4:axios.CancelToken.source()new CancelToken(...) 区别?

方式特点
CancelToken.source()✅ 简洁封装了 token + cancel
new CancelToken(...)✅ 灵活但略繁琐

建议用 source(),更易读。


✅ Q5:为什么是 ?.('取消重复请求') 这么奇怪的语法?

?.(...) 是可选链函数调用写法,防止 undefined() 报错。更安全。


🏁 总结

通过 Axios 的 CancelToken + pendingRequestMap,我们实现了:

重复请求自动取消
请求完成后自动清理内存
异常中判断是否是取消请求
封装逻辑易复用、可维护


📌 附:可搭配使用场景建议

场景是否建议取消前一个请求
搜索建议输入框✅ 是,避免请求风暴
点击切换页面✅ 是,避免残留请求
并发上传多个文件❌ 否,每个请求应独立
表单重复提交✅ 是,防止多次创建
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值