一、背景
项目中按钮请求接口出现用户短时间内连续点击导致系统出现异常。考虑在前端对相同的请求进行拦截。
二、实现思路
1.按钮点击之后禁用,间隔一定时间或接口请求完成后启用,达到防止点击的目的。
①禁用一定时间后重新启用的时机不好判断,可能接口还没请求结束就启用的话还会出现上述问题
②在接口的请求回调中禁用,因为项目已经是上线项目,设计范围太广,修改工作量较大。
综上所述,放弃使用禁用按钮的思路
2.考虑在axiso请求拦截器中处理相同请求
在接口请求时记录请求的url,再次请求时判断当前的url是否在记录内。如果在记录内则取消请求。当请求成功后则移除记录值。从而达到不允许相同接口同时请求的目的。
三、具体实现
1.增加pending字段用来保存请求的接口
2.声明 cancelToken
let pending = []; // 声明一个数组用于存储每个请求的取消函数和axios标识
let cancelToken = axios.CancelToken;
let removePending = (config) => {
for (let i in pending) {
if (pending[i].url === config.url) { // 在当前请求在数组中存在时执行取消函数
pending[i].f(); // 执行取消操作
pending.splice(i, 1); // 把pending记录删掉
}
}
}
instance.interceptors.request.use(config => {
removePending(config); // 在一个axios发送前执行一下判定操作,在removePending中执行取消操作
config.cancelToken = new cancelToken(function executor (c) { // 本次axios请求的配置添加cancelToken
pending.push({
url: config.url,
f: c
});
})
return config
})
// response 拦截器
instance.interceptors.response.use(
response => {
removePending(response.config); // 在一个axios响应后再执行一下取消操作,把已经完成的请求从pending中移除
},
error => {
if (error.response) {
} else if (error.__CANCEL__) {
console.log('操作过于频繁,稍后重试')
} else {
Message.error('请求出错')
}
return Promise.reject(error) // 返回接口返回的错误信息
}
)