👏最近项目刚好需要该功能,趁此机会学习一下,毕竟封装好了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方法,非常欢迎分享,讨论一下