前端axios取消请求详解:原理、用法与批量处理

作者:小满

时间:2026-10-25

浏览:498

本文详细解析前端axios取消请求的两种主要用法:CancelToken构造函数与source方法。通过源码追踪CancelToken、Cancel及xhr适配器,阐明基于Promise状态控制的取消机制,并给出封装axios后批量取消及路由切换时取消请求的实战方案。

文章目录

应用场景

在前端开发中,取消HTTP请求是一项常见需求。以下是两个典型的工作场景:

  • 在Tab切换刷新列表数据时,若多个Tab共用同一变量存储数据,且请求存在延迟,极易导致数据展示错乱。
  • 在执行文件导出或下载操作时,用户可能需要中途取消任务。

如何取消请求

针对HTTP请求的取消,axios官方文档提供了两种实现方式:

第一种方式是使用 CancelToken。

const { CancelToken, isCanCel } = axios;
const source = CancelToken.source();
axios.get('/user/12345', {
  cancelToken: source.token
}).catch(thrown => {
  if (isCancel(thrown)) {
    // 获取 取消请求 的相关信息
    console.log('Request canceled', thrown.message);
  } else {
    // 处理其他异常
  }
});
axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})
// 取消请求。参数是可选的,参数传递一个取消请求的相关信息,在 catch 钩子函数里能获取到
source.cancel('Operation canceled by the user.');

第二种方式是在构造函数 CancelToken 中传递一个 executor 函数。这种方式的优点在于,可以使用同一个 cancel token 来取消多个请求。

const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // 参数 c 也是个函数
    cancel = c;
  })
});
// 取消请求,参数用法同上
cancel();

项目中用法示例

在实际项目中,通常会对 axios 进行二次封装,以统一处理请求、响应、状态码及业务 code。以下是一个常见的项目级 request.js 示例:

import axios from 'axios'
import store from '@/store'
import { getToken } from '@/utils/auth'
// 创建一个 axios 实例,并改变默认配置
const service = axios.create({
  baseURL: process.env.BASE_API, // api 的 base_url
  timeout: 5000 // request timeout
})
// 请求拦截
service.interceptors.request.use(
  config => {
    // Do something before request is sent
    if (store.getters.token) {
      // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // Do something with request error
    console.log(error) // for debug
    Promise.reject(error)
  }
)
// 响应拦截
service.interceptors.response.use(
  response => response,
  error => {
    alert(error)
    return Promise.reject(error)
  }
)
export default service

若需为特定请求添加取消功能,需在调用 API 时传入 cancelToken 选项。具体使用示例如下:

// api.js
import request from 'request'
export function getUsers(page, options) {
  return request({
    url: 'api/users',
    params: {
      page
    },
    ...options
  })
}
// User.vue
import { CancelToken, isCancel } from 'axios'
import { getUsers } from 'api'
...
cancel: null
...
toCancel() {
  this.cancel('取消请求')
}
getUsers(1,
  {
    cancelToken:  new CancelToken(c => (this.cancel = c))
  }
)
.then(...)
.catch(err => {
  if (isCancel) {
    console.log(err.message)
  } else {
    ...
  }
})

通过上述方式,即可在封装好的 axios 中顺畅地取消特定请求。其核心原理在于调用 API 时传入 cancelToken 配置项,从而在业务代码中能够针对特定请求执行取消操作。

批量取消请求

前文提到的第二种方法指出,通过指定相同的 cancel token 可实现取消。但在上述项目示例中,难以直接获取到相同的 cancel token。我们可以换一种思路:使用数组保存每个需要取消的 cancel token,然后遍历数组逐一调用。具体实现如下:

// User.vue
import { CancelToken, isCancel } from 'axios'
import { getUsers } from 'api'
...
cancel: []
...
toCancel() {
  while (this.cancel.length > 0) {
    this.cancel.pop()('取消请求')
  }
}
getUser1(1,
  {
    cancelToken:  new CancelToken(c1 => (this.cancel.push(c1)))
  }
)
getUser2(2,
 {
  cancelTokem: new CancleTokem(c2 => (this.cancel.push(c2)))
 }
)

切换路由时,取消请求

前文已介绍如何取消单个请求及页面内批量 abort 的方法。此外,还有一种常见需求:在切换路由时取消所有请求。此处简要说明思路:在请求拦截器中统一添加 token,并设置全局变量 source 控制一个 cancel token,在路由变化时调用 cancel 方法即可。

http.interceptors.request.use(config => {
    config.cancelToken = store.source.token
    return config
}, err => {
    return Promise.reject(err)
})
router.beforeEach((to, from, next) => {
    const CancelToken = axios.CancelToken
    store.source.cancel && store.source.cancel()
    store.source = CancelToken.source()
    next()
})
// 全局变量
store = {
    source: {
        token: null,
        cancel: null
  }
}

取消请求的实现原理

cancelToken 的 source 方法维护了一个对象,其中包含 token 令牌和 cancel 方法。token 源自构造函数 CancelToken,调用 cancel 方法后,token 内部的 promise 状态变为 resolved,进而触发 xhr 的 abort 方法,成功取消请求。接下来,我们将通过一个简单的取消请求示例来深入分析其实现过程:

var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/get?name=xmz', {
    cancelToken : source.token
}).then((response)=>{
    console.log('response', response)
}).catch((error)=>{
    if(axios.isCancel(error)){
        console.log('取消请求传递的消息', error.message)
    }else{
        console.log('error', error)
    }
})
// 取消请求
source.cancel('取消请求传递这条消息');

这是一个简单的取消请求示例。我们从最开始的axios.CancelToken入手,前往axios/lib/axios.js文件进行查看。

axios.CancelToken = require('./cancel/CancelToken');

很快就能找到 CancelToken。在示例中调用了 source 方法,因此需要前往axios/lib/cancel/CancelToken.js文件查看该 source 方法的具体实现。

CancelToken.source = function(){
    var cancel;
    var token = new CancelToken(function executor(c) {
        cancel = c
    })
    return {
        token : token,
        cancel : cancel
    }
}

source 方法逻辑简单,主要返回一个包含 token 和 cancel 属性的对象。由于 token 和 cancel 均通过 CancelToken 构造函数生成,因此需在该文件中向上查找 CancelToken 函数。

function CancelToken (executor){
    // ...
    // 判断executor是一个函数,不然就报错
    var resolvePromise;
    this.promise = new Promise(function(resolve){
        resolvePromise = resolve;
    })
    var token = this;
    // 以上token现在有一个promise属性,是一个未成功的promise对象;
    executor(function cancel(message){
        if(token.reason){
            return;
        }
        token.reason = new Cancel(message);
        resolvePromise(token.reason);
    })
    // 这个cancel函数就是 上面函数中的cancel,也就是source.cancel;
}

至此已知 source.cancel 是一个函数,souce.token 是一个实例化对象。暂且了解这些,继续查看文章开头的示例,接下来是发送请求。代码最后一行执行souce.cancel();,souce.cancel 即为触发取消请求的函数。现在回头查看前述 cancel 函数,它给 token 添加了一个 reason 属性。接下来查看这个 reason 属性的定义,即 Cancel 构造函数,位于axios/lib/cancel/Cancel.js文件中。

function Cancel(message){
    this.message = message
}

Cancel 的实现非常简单,仅为实例化对象添加一个 message 属性。因此,现在 token.reason 是一个包含 message 属性的对象。继续回到 cancel 函数,resolvePromise 函数被执行,使得 token.promise 对象从原本未成功状态变为成功状态,并将 token.reason 对象作为参数传递。简单总结:执行取消函数,即让 token 的 promise 状态变为成功。此时分析似乎中断,promise 变为成功状态后如何取消请求?虽然当前同步代码执行完毕,但请求尚未发出,因此还需查看发送请求的函数。

在分析发送请求前,回顾开头示例,与普通 GET 请求相比,配置对象中多了一个 cancelToken 属性,其值为 token。该属性具体起何作用?前往axios/lib/adapters/xhr.js一探究竟(此处仅截取关于 cancelToken 的部分)。

// 在发送请求之前,验证了cancelToken,看来此处就是用来取消请求的;
if(config.cancelToken){
    // 具体是如何取消的,是在这个判断内定义的;
    config.cancelToken.promise.then(function(cancel){
        request.abort();
        reject(cancel);
        request = null;
    })
}
// 发送请求
request.send(requestData);

仔细观察,这只是一个 promise 的 then 函数,仅在 promise 状态变为成功后执行。前文分析表明,cancel 操作会使该 promise 状态变为成功。因此,若执行了取消请求函数,该 then 便会执行,从而取消发送请求,并将发送请求的 promise 变为 reject 状态,最终被 axiox.get().catch() 捕获。流程已清晰,最后总结:执行 cancel 使 token 的 promise 变为成功。在真正发送请求前,验证 token.promise 的状态是否已改变;若已改变,则取消请求。这便是取消请求背后的简单思想。

以上就是axios取消请求总结的详细内容,更多关于axios取消请求的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章