vue3+ts,封装axios(取消重复请求)

697 阅读2分钟

👏最近项目刚好需要该功能,趁此机会学习一下,毕竟封装好了axios事半功倍。

我们直接上代码,代码里会有注释和原因

/**
 * @description 为封装vue3+ts的axios时,取消重复请求,在第一次请求返回前,不请求第二次
 * @description 主要原理使用Map的唯一键值对,请求该接口时,拼接接口url和参数等信息保存到一个map中,再次请求接口时,先判断map中是否存在同名key,如果存在key,则中断该请求,在返回时,删除返回的key;反之在map中新增key。
 */

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import qs from 'qs'

// 扩展AxiosRequestConfig接口,加入自定义的配置参数
declare module 'axios' {
  export interface AxiosRequestConfig {
    repeatRequest?: boolean  // 是否为重复请求
    // 该处还可添加更多自定义配置(如是否返回原始数据、错误提示方式)
  }
}

// 用于装载状态处于请求中的axios请求
let pendingMap = new Map()

// 获取处于pendingMap的key
function getRequestKey(config: AxiosRequestConfig) {
  return (config.method || '') + config.url + '?' + qs.stringify(config.data)
}

// 给pendingMap设置值
function setPendingMap(config: AxiosRequestConfig) {
  /*
  * Axios有两个取消请求的API,AbortController和CancelToken,新项目中建议使用AbortController
  * 我们通过AbortController(控制器对象).signal返回一个AbortSignal绑定到axios请求的config配置中,然后就可以通过该AbortController.abort中止请求。
  */
  const controller = new AbortController()
  config.signal = controller.signal
  const key = getRequestKey(config)

  if (pendingMap.has(key)) {
    controller.abort()
  } else {
    pendingMap.set(key, controller)
  }
}

/*
* 后续这些就是axios封装的老套路了:创建=>请求拦截=>返回拦截=>导出封装
*/

const service: AxiosInstance = axios.create({
  timeout: 3000,
  baseURL: 'http://127.0.0.1:3000'
})

service.interceptors.request.use(
  (config) => {
    if (!config.repeatRequest) {
      setPendingMap(config)
    }
    return config
  },
  (err) => {
    console.log('err', err)
    return Promise.reject(err)
  }
)

service.interceptors.response.use((response: AxiosResponse) => {
  const config = response.config
  const key = getRequestKey(config)
  pendingMap.delete(key)
  console.log('response', response)

  if (response.status === 200) {
    return response.data
  } else {
    /**
     * 可在此处做错误处理
     * 此处的处理通常为网络请求状态码有问题时
     * 通常项目中根据UI库在页面使用Toast提示请求错误
     */
    Promise.reject()
    return response
  }
})

// 错误处理
service.interceptors.response.use(undefined, (e) => {
  /**
   * 可在此处做错误处理
   * 此处通常重复请求时会调起
   */
  console.log('e', e)
})

export default service

这里只实现了取消重复请求(在第一次请求返回前,都不允许发起相同url、method、data的请求)

如果有什么别的更好的想法、别的好的封装axios方法,非常欢迎分享,讨论一下[灵光一现]