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;

  });

}

笔记

相关推荐
手握风云-19 小时前
JavaEE 进阶第四期:开启前端入门之旅(四)
前端
魔云连洲19 小时前
React中的合成事件
前端·javascript·react.js
六月的可乐20 小时前
【干货推荐】AI助理前端UI组件-悬浮球组件
前端·人工智能·ui
呼啦啦呼_20 小时前
Echarts自定义地图显示区域,显示街道学校等区域,对原有区域拆分
前端
浩星20 小时前
iframe引入界面有el-date-picker日期框,点击出现闪退问题处理
前端·vue.js·elementui
技术钱20 小时前
element plus 多个form校验
前端
yume_sibai20 小时前
HTML HTML基础(3)
前端·html
米花丶20 小时前
JSBridge安全通信:iOS/Android桥对象差异与最佳实践
前端·webview
唐•苏凯21 小时前
ArcGIS Pro 遇到严重的应用程序错误而无法启动
开发语言·javascript·ecmascript
萌萌哒草头将军21 小时前
🚀🚀🚀 Oxc 恶意扩展警告;Rolldown 放弃 CJS 支持;Vite 发布两个漏洞补丁版本;Rslib v0.13 支持 ts-go
前端·javascript·vue.js