axios取消http请求
# 前言
在前端项目中,经常用axios
作为http
请求接口的插件。
在开发中,我们考虑如下三种场景:
(1)固然可以通过防抖亦或是节流,限制用户在频繁点击按钮的场景下
http
请求的次数。那么,如果前一个http
请求已经发出了,那么如何取消它呢?
(2)或者在另一种场景下,如果接口响应不是那么及时,第一次请求还在
pending
状态;第二次请求的参数和第一次不同,第一次请求的结果返回了,但是第二次请求还在pending
,我们拿到的数据其实不是我们想要的。
(3)还有一种场景,如果在页面卸载或者组件时,某些还在
pending
状态的http
请求是无效的,纯属浪费资源。
以上三种场景的相同点就是需要取消pending
状态的http
请求。
# 问题解决
在Web API中,MDN文档中写道:
AbortController
接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求。 你可以使用AbortController()
构造函数创建一个新的AbortController
对象。使用AbortSignal
对象可以完成与异步操作的通信
基于AbortController
,我们可以封装一个apiController
类。在axios
的request
拦截器中比对,控制器集合对象中是否存在相同的控制器,如不存在,则添加当前http
请求的相关信息,一个请求对应生成一个控制器对象controller
;若存在,则调用控制器,取消前一个请求,添加新的控制器;在response
拦截器中移除对应的控制器。
apiController
类封装如下:
export class ApiController {
constructor() {
this.controllerMap = new Map()
}
// 获取控制器对象
getControllerMap() {
return this.controllerMap;
}
// 创建请求的唯一标识
createRequestId(config) {
const { method, url, data } = config;
return `${method}${url}${JSON.stringify(data)}`;
}
// 取消待处理请求
cancelPendingRequest(requestId, reason) {
const controllerMap = this.getControllerMap();
// 如果已存在相同请求,取消旧请求
controllerMap.get(requestId).abort(reason);
controllerMap.delete(requestId);
}
// 添加请求到待处理列表
addRequestToQueue(config) {
const controllerMap = this.getControllerMap();
const requestId = this.createRequestId(config);
if (controllerMap.has(requestId)) {
// 如果已存在相同请求,取消旧请求
this.cancelPendingRequest(requestId, '重复请求,取消前一次')
}
const controller = new AbortController();
config.signal = controller.signal;
controllerMap.set(requestId, controller);
}
// 移除待处理列表
removeRequestFromQueue(config) {
const requestId = this.createRequestId(config);
const controllerMap = this.getControllerMap();
if (controllerMap.has(requestId)) {
controllerMap.delete(requestId);
}
}
// 清除所有的控制器
clear() {
const controllerMap = this.getControllerMap();
controllerMap.clear();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
ApiController
类使用如下
const apiController = new ApiController();
const service = axios.create();
service.interceptors.request.use((config)=>{
apiController.addRequestToQueue(config)
return config;
})
service.interceptors.response.use((response)=>{
apiController.removeRequestFromQueue(response.config)
return response;
},error(error)=>{
if (axios.isCancel(error)) {
apiController.removeRequestFromQueue(error.config)
} else{
/**其他错误处理 */
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
编辑 (opens new window)
上次更新: 2025/09/08, 03:11:23