 axios取消http请求
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
