在 web项目开发的过程中,经常会遇到客服端重复发送请求的场景,如果开发者不对重复的请求进行相应的处理,可能会导致项目崩溃,服务器瘫痪等各种各样的问题出现。通过 axios为例,了解解决重复请求的问题答案。
axios是一个基于 Promise的 HTTP客户端,同时支持浏览器和 node.js环境。是一个十分优秀的 HTTP客户端,被广泛运用在大量的 web项目中。
let xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.xxx.com",true);
xhr.send();
setTimeout(() => xhr.abort(),300);
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/api/user', {
name:'admin'
}, {
cancelToken: source.token
})
source.cancel('取消请求'); // 取消请求,参数可选
此外,也可以通过调用 CancelToken的构造函数来创建 CancelToKen,如下:
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/api/user', {
cancelToken: new CancelToken(function excutor(c){
cancel = c;
})
});
cancel(); // 取消请求
当请求方式,请求 URL和请求携带参数都一样时,就可以认为是相同的请求。因此在每次发起请求时,可以根据当前请求的请求方式、请求 URL地址和请求携带参数来生成一个唯一的 key;同时为每个请求创建一个专属的 CancelToken,然后将 key 和 Cancel 函数以键值对的形式保存到 Map对象中,使用 Map对象的好处是可以快速判断是否有重复的请求,具体实现如下:
import qs from "qs"
const pendingRequest = new Map();
// GET --> params, POST --> data
const requestKey = [method, url, qs.stringify(params), qs.stringify(data)].join('&');
const cancelToken = new CancelToken(function excutor(cancel){
if(!pendingRequest.has(requestKey)){
pendingRequest.set(requestKey,cancel)
}
})
出现重复请求时,就可以调用 cancel函数来取消之前已经发出的请求。在取消请求之后,还需要把取消的请求从 pendingRequest中移除。
因为需要对所有的请求都进行处理,所以可以考虑使用 axios的拦截器机制来实现取消重复请求的功能。
axios的制作者为开发人员提供了请求拦截器和响应拦截器,各自的作用如下:
在配置请求拦截器和响应拦截器之前,需要先定义三个辅助函数:
function generateReqKey(config){
const {method, url, params, data } = config;
return [method, url, qs.stringify(params), qs.stringify(data)].join('&')
}
const pendingRequest = new Map();
function addPendingRequest(config){
const requestKey = generateReqKey(config);
config.cancelToken = config.cancelToken || new axios.CancelToken((cancel)={
if(!pendingRequest.has(requestKey)){
pendingRequest.set(requestKey,cancel)
}
});
}
function removePendingRequest(config){
const requestKey = generateReqKey(config);
if(pendingRequest.has(requestKey)){
const cancelToken = pendingRequest.get(requestKey);
cancelToken(requestKey);
pendingRequest.delete(requestKey);
}
}
创建好这三个函数以后,就可以设置请求拦截器和响应拦截器
axios.interceptors.request.use(
function (config) {
removePendingRequest(config); // 检查是否存在重复请求
addPendingRequest(config); // 将当前请求信息添加到 pendingRequest对象中
return config;
},
(error) => {
return Promise.reject(error);
}
);
axios.interceptors.response.use(
(response) => {
removePendingRequest(response.config); // 从 pendingRequest对象中移除请求
return response;
},
(error) => {
removePendingRequest(error.config || {}); // 从 pendingRequest对象中移除请求
if(axios.isCancel(error)){
console.log(error.message);
}else {
// 自行处理异常请求
}
return Promise.reject(error);
}
);
这里是万物之恋,我们下次再见了!