背景
今天发现系统中某些页面存在一个接口请求多次的情况,虽然是在写业务代码的时候导致了重复调用,但是由此觉得应该在axios请求的时候,加入接口重复请求取消的设计。
方案
经过调研发现了几种解决接口调用重复的方案
- 利用防抖、截流的思想,在一段时间内针对请求只发一次,从交互层面防止。
- 封装loading,发现有请求的时候直接loading,请求结束后再closeloading,从交互层面防止。
- 在axios请求中封装,使用内部提供CancelToken来取消请求,但是在v0.22.0中已经被废弃,推荐使用AbortController来取消请求
实现
前两种实现就不说了,实现的主要就是第三种。
1.第一种可以使用一些第三方库来实现,比如点击某个按钮,一段时间之后再发出去请求,lodash库的debounce函数,就自己可以不用封装防抖函数了。
2.在有接口请求的地方开启loading,请求结束以后closeloading。或者可以在axios中开启一个全局loading,然后通过计数的方式,开启一个请求变量+1,请完成变量-1,等变量为0再closeLoading。
3.在axios中使用abortController.abort()来取消请求。
const pendingMap = new Map(); // 用来存放url的值
/**
* 生成每个请求唯一的键
* @param {*} config
* @returns string
*/
function getPendingUrl(config) {
let { url, method, params, data } = config;
if (typeof data === 'string') data = JSON.parse(data); // response里面返回的config.data是个字符串对象
return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&');
}
/**
* 取消请求
* @param {*} config
*/
function removePending(config) {
const url = getPendingUrl(config);
if (pendingMap.has(url)) {
// 如果当前请求在等待中,取消它并将其从等待中移除
const abortController = pendingMap.get(url);
if (abortController) {
abortController.abort(url);
}
pendingMap.delete(url);
}
}
/**
* 添加请求到等待中
* @param {*} config
*/
function addPending(config) {
removePending(config);
const url = getPendingUrl(config);
const controller = new AbortController();
config.signal = config.signal || controller.signal;
if (!pendingMap.has(url)) {
// 如果当前请求不在等待中,将其添加到等待中
pendingMap.set(url, controller);
}
}
/**
* 清除所有请求
*/
function removeAllPending() {
pendingMap.forEach((abortController) => {
if (abortController) {
abortController.abort();
}
});
clear();
}
/**
* 清空队列
*/
function clear() {
pendingMap.clear();
}
在请求拦截器中:
request.interceptors.request.use(
(config) => {
addPending(config);
return config;
},
(error) => Promise.reject(error)
);
在响应拦截器中:
request.interceptors.response.use(
(response) => {
response && removePending(response.config);
....
return response;
},
(error) => {
response && removePending(response.config);
if (error.name === 'CanceledError') {
console.log("取消的请求")
}
}
);
写一个测试用例,打开控制台网络:
测试OK啦!!!
参考了vue-vben-admin的源码!
自己测试之后是能用的,有问题的话请大佬们指出,感恩!