取消axios请求

546 阅读2分钟

应用场景:用户发起多个并发请求,但是token现在是失效的,这个时候页面会弹出多个接口返回的token失效的报错信息,很显然这不是我们想要的,如果发现一个接口请求token失效以后,可不可取消掉其他的后续请求,让用户直接去重新登录去,很显然是可以的。

axios取消请求

官方给出的示例如下

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('请求取消了');

但是这样处理显然不够便捷,官方还提供了这样的方法,通过传递一个 executor 函数到 CancelToken 的构造函数来创建一个 cancel token

const CancelToken = axios.CancelToken; 
let cancel; 
axios.get('/user/12345', { 
   cancelToken: new CancelToken(function executor(c) { 
      // executor 函数接收一个 cancel 函数作为参数 
      cancel = c; 
   }) 
}); 
// 取消请求 
cancel();

还可以使用同一个 cancel token 或 signal 取消多个请求

const controller = new AbortController(); 
const CancelToken = axios.CancelToken; 
const source = CancelToken.source(); 
axios.get('/user/12345', { 
    cancelToken: source.token, 
    signal: controller.signal 
}).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.'); 
     // 或 
     controller.abort(); // 不支持 message 参数

以上这些是官方给出的一些示例,具体到咱们实际项目要怎么用呢,接下来开始 以下采用了官方提供的 通过传递一个 executor 函数到 CancelToken 的构造函数来创建一个cancel token的方案。 首先全局声明一个变量来存储要取消的axios请求,在main.js中声明 Vue.$requestList=[]

// 创建 axios 实例
const request = axios.create({
  // API 请求的默认前缀
  baseURL: process.env.VUE_APP_API_BASE_URL,
  timeout: 90000 // 请求超时时间
})

const CancelToken = axios.CancelToken

// 异常拦截处理器
const errorHandler = (error) => {
  if (error.response) {
    const data = error.response.data
    // 从 localstorage 获取 token
    const token = storage.get(token)
    if (error.response.status === 401) {
      notification.error({
        message: '没有权限',
        description: '权限校验失败,请重新登录'
      })
      //这里取消axios请求
      Vue.$requestList.forEach(item => {
        item()
      })
     store.dispatch('Logout').then(() => {
           //退出登录以后的回调
     })
    }
    if (error.response.status === 500 || error.response.status === 502) {
      notification.error({
        message: '服务器错误',
        description: '服务器内部错误'
      })
    }
  }
  if (axios.isCancel(error)) { // 取消请求的情况下,终端Promise调用链
    return new Promise(() => {});
  } else {
    return Promise.reject(error)
  }
}

// request interceptor
request.interceptors.request.use(config => {
  //通过传递一个 executor 函数到 `CancelToken` 的构造函数来创建一个 cancel token
  config.cancelToken = config.cancelToken = new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数作为参数
    //这里把cancel函数push到全局变量中
    Vue.$requestList.push(c)
  })
  const token = storage.get(token)
  // 如果 token 存在
  // 让每个请求携带自定义 token 请根据实际情况自行修改
  if (token) {
    config.headers.common['token'] = token
  }
  return config
}, errorHandler)

// response interceptor
request.interceptors.response.use(async (response) => {
  const token = storage.get(token)
  let errCodeArr = [1001, 1004, 1005]
  if (response.data.code == 1006) {  //用户未登录
    notification.error({
      message: '没有权限',
      description: '权限校验失败,请重新登录'
    })
    Vue.$requestList.forEach(item => {
      item()
    })
     store.dispatch('Logout').then(() => {
         //退出登录的后续回调
      })
  } else if (errCodeArr.includes(response.data.code)) {
    notification.error({
      message: response.data.message,
    })
  }
  return response.data
}, errorHandler)

实测查看可以看到后续的请求被取消掉了

微信截图_20221222111929.png