1、场景
2种场景:
假设页面中有一个按钮,用户点击按钮后会发起请求。如果没有对该按钮进行控制,当用户快速点击按钮时,会发出重复请求。
假设在工单结果查询页面中,用户可以根据 “已审批”、“未审批” 和 “全部” 3 种查询条件来查询工单结果。如果请求的响应比较慢,当用户在不同的查询条件之前快速切换时,就会产生重复请求。
处理有三种情况:(第一次请求A,第二次请求B)
1、取消第一次A ,请求第二次B
2、请求第一次A,取消第二次B
3、请求第一次A,取消第二次B,将A请求结果给B
这里用第二种
理解小 tips:
1、定义 pendingRequests 为 map 对象的目的是为了方便我们查询它是否包含某个 key,以及添加和删除 key。添加 key 时,对应的 value 可以设置用户自定义的一些功能参数。
2、 config 是 axios 拦截器中的参数,包含当前请求的信息
3、 在请求发出前检查当前请求是否重复
4、 在请求拦截器中,生成上面的 requestKey,检查 pendingRequests 对象中是否包含当前请求的 requestKey: 有:说明是重复的请求,cancel 掉当前请求;没有:把 requestKey 添加到 pendingRequests 对象中
请求拦截
1、检查是否存在重复请求,若存在则取消已发的请求
2、把当前请求添加到pendingRequest对象中
2、代码
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Axios 取消重复请求示例</title>
<script src="https://cdn.bootcdn.net/ajax/libs/qs/6.9.6/qs.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
</head>
<body>
<h3>Axios 取消重复请求示例</h3>
<button onclick="sendRequest()">发起请求</button>
<script>
// 判断重复,存储所有 pending 状态的请求
const pendingRequest = new Map();
// 根据 url、method、params 等生成唯一标识,大家可以自定义自己的生成规则
function generateReqKey(config) {
const { method, url, params, data } = config;
return `${url}/${JSON.stringify(params)}/${JSON.stringify(data)}&request_type=${method}`;;
}
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 cancel = pendingRequest.get(requestKey);
cancel(requestKey);
pendingRequest.delete(requestKey);
}
}
// 取消重复
// 请求拦截器:请求发送前统一执行某些操作,比如在请求头中添加 token 字段。
// 响应拦截器:接收到服务器响应后统一执行某些操作,比如发现响应状态码为 401 时,自动跳转到登录页。
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);
}
);
async function sendRequest() {
console.dir(pendingRequest);
const response = await axios.get(
"http://localhost:3000/api/user"
);
console.log(response.data);
}
</script>
</body>
</html>