axios之CancelToken取消请求

v0.22.0 开始,Axios 支持以 fetch API 方式------ AbortController 取消请求

此 API 从 v0.22.0 开始已被弃用,不应在新项目中使用

官网链接

1. 背景

最近项目中遇到一个场景,当连续触发一个请求时,如果是同一个接口,则保留最后一次的请求,之前的请求取消。

查阅了下axios文档,有一个属性CancelToken,把这个添加到axios配置中

2. 使用

1:在request时,添加cancelToken

javascript 复制代码
  request: [
    (config: AxiosRequestConfig) => {
      const cacheKey = `${config.method}${config.url}`
     
      if (config.autoCancel) {
        removeCache(cacheKey)
      }
      config.cancelToken = new axios.CancelToken((c) => {
        caches[cacheKey] = c
      })
      return config
    },
    (error: any) => Promise.reject(error),
  ],

2:在reponse时,删除key

javascript 复制代码
  response: [
    (res: AxiosResponse) => {
      const cacheKey = `${res.config.method}${res.config.url}`
      if (res.config.autoCancel) {
        removeCache(cacheKey)
      }
      return res
    },
    (error: any) => Promise.reject(error),
  ],

3:判断是否存在重复请求

javascript 复制代码
const caches: Record<string, Canceler> = {}
function removeCache(key: string) {
  if (caches[key]) {
    
    caches[key]()
    delete caches[key]
  }
}

这里的autoCancel 是为了解决url相同,请求参数不同时,自定义添加的,具体请求方式可以根据这个值来决定是否开启cancelToken

3. 全部代码

javascript 复制代码
/**
 * 通过取消重复请求解决请求"竞态"问题
 * - 如何定义"重复":method和url相同
 */
import axios, { AxiosRequestConfig, Canceler, AxiosResponse } from 'axios'

const caches: Record<string, Canceler> = {}
function removeCache(key: string) {
  if (caches[key]) {
    caches[key]()
    delete caches[key]
  }
}

const cancelInterceptors = {
  request: [
    (config: AxiosRequestConfig) => {
      const cacheKey = `${config.method}${config.url}`
      if (config.autoCancel) {
        removeCache(cacheKey)
      }
      config.cancelToken = new axios.CancelToken((c) => {
        caches[cacheKey] = c
      })
      return config
    },
    (error: any) => Promise.reject(error),
  ],
  response: [
    (res: AxiosResponse) => {
      const cacheKey = `${res.config.method}${res.config.url}`
      if (res.config.autoCancel) {
        removeCache(cacheKey)
      }
      return res
    },
    (error: any) => Promise.reject(error),
  ],
}

export default cancelInterceptors

在封装的axios里面添加配置

javascript 复制代码
// 往request请求中添加配置
service.interceptors.request.use(...cancelInterceptors.request)

// 往response请求中添加配置
service.interceptors.response.use(...cancelInterceptors.response)

在response失败error中axios返回了一个失败状态axios.isCancel(error)

javascript 复制代码
(error: AxiosError) => {
    // if (axios.isCancel(error) && error.message === SCRM_CANCEL_MESSAGE) {
    //   // 被手动取消的数据统计接口,不展示提示
    if (axios.isCancel(error)) {
      // 被取消的接口,不展示提示
    } else {
      message.error(error.response?.statusText || error.message || '网络错误')
    }

    // 网络层面错误,如接口地址写错了会走到这里
    return Promise.reject(error)
  }

3. 原理

source file:axios/lib/adapters/xhr.js

1:创建请求

javascript 复制代码
var request = new XMLHttpRequest()

if (config.cancelToken) {
  // Handle cancellation
  config.cancelToken.promise.then(function onCanceled(cancel) {
    if (!request) {
      return;
    }

    request.abort();
    reject(cancel);
    // Clean up request
    request = null;
  });
}

2:创建新的取消

在source file:axios/lib/cancel/CancelToken.js

javascript 复制代码
  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

2:取消请求

在axios/lib/adapters/xhr.js文件中取消**request.abort();**请求,

javascript 复制代码
if (config.cancelToken) {

  // Handle cancellation

  config.cancelToken.promise.then(function onCanceled(cancel) {

    if (!request) {

      return;

    }



    request.abort();

    reject(cancel);

    // Clean up request

    request = null;

  });

}

笔记

相关推荐
万少7 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站10 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名12 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫12 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊12 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter12 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折13 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_13 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
Angelial13 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js
jiayu13 小时前
Angular学习笔记24:Angular 响应式表单 FormArray 与 FormGroup 相互嵌套
前端