axios 全局错误处理和请求取消-CSDN博客

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

在这里插入图片描述

这两个功能都是用拦截器实现。

前景提要
ts 简易封装 axios统一 API
实现在 config 中配置开关拦截器

全局错误处理

在构造函数中添加一个响应拦截器即可。在构造函数中注册拦截器的好处是无论怎么实例化封装类这个错误拦截器都会被注册进实例。

其中有个注意点就是请求取消。取消请求会导致响应 promise 状态为 rejected这样就会触发响应拦截器的 onRejected 回调。因此要单独处理请求的请求情况将它与请求错误区分开来。

class HttpRequest {
   	private readonly instance: AxiosInstance;
  
  	constructor(config: MyAxiosRequestConfig) {
      	this.instance = axios.create(config);
      
				// axios http 错误处理超出 2xx 范围的 http 状态码都会触发该函数
        this.instance.interceptors.response.use(null, (error: AxiosError) => {
            // 手动取消请求会导致“错误”触发
            if (error.message === "canceled") alert("请求取消成功");

            const { response } = error;
            // 1. 请求超时 && 网络错误单独判断因为没有 response
            if (error.message.indexOf("timeout") !== -1) alert("请求超时请您稍后重试");
            if (error.message.indexOf("Network Error") !== -1) alert("网络错误请您稍后重试");
            // 2. 根据 http 服务器响应的错误状态码做不同的处理
            if (response) {
                switch (response.status) {
                    case 404:
                        alert("你所访问的资源不存在");
                        break;
                    case 500:
                        alert("服务异常");
                        break;
                    default:
                       	alert("请求失败");
                }
            }
            // 3. 服务器结果都没有返回(可能服务器错误可能客户端断网)断网处理:也可以跳转到断网页面
            if (!window.navigator.onLine) alert("服务器错误或者无网络"); // router.replace("/500");
            throw error;
        });
    }
}

取消请求

axios 取消请求的方式

axios 取消请求有两种 api。一种是 AbortController一种是古老的 CancelToken 已经被弃用了。

AbortController - Web API 接口参考 | MDN

我们主要使用第一种方式

  1. 实例化取消控制器接口控制器对象有一个信号标记signal
  2. 将该标记配置给 axios 同名的 signal配置
  3. 控制器对象调用abort()方法就能取消被标记了的请求。
const controller = new AbortController();

axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   //...
});
// 取消请求
controller.abort()

封装取消请求功能

取消请求也是个基础功能因此和全局错误拦截器一样在构造函数中注册拦截器。

取消请求

  1. 为每一个请求生成一个控制器 controller并添加 signal
  2. 维护一个 map以 url 为 key对应的 controller 为 value
  3. 要取消哪个请求就通过 url获取它的 controller 来取消
  4. 在全局响应拦截器中给所有请求添加 signal并在请求结束后从 map 中剔除该 url 对应的 controller

封装类暴露两个方法

  1. 取消全部请求
  2. 根据 url 取消请求
class HttpRequest {
    private readonly instance: AxiosInstance;
    private readonly abortControllerMap: Map<string, AbortController>;

  	constructor(config: MyAxiosRequestConfig) {
      	this.instance = axios.create(config);

        // 为每个请求都生成一个 signal并以 url 为 key 添加入 map
        this.instance.interceptors.request.use(
            config => {
                // 如果具体方法中设置了 signal这里就不再添加避免覆盖。
                if (config.signal) return config;

                const controller = new AbortController();
                config.signal = controller.signal;
              
                const url = config.url || "";
                this.abortControllerMap.set(url, controller);
              
                return config;
            },
            (err: AxiosError) => {
                throw err;
            }
        );
        // 响应完从map中去除 url
        this.instance.interceptors.response.use(
            res => {
                const url = res?.config.url || "";
                this.abortControllerMap.delete(url);
                return res;
            },
            (err: AxiosError) => {
                const url = err?.config?.url || "";
                this.abortControllerMap.delete(url);
                throw err;
            }
        );
    }

    /**
     * 取消全部请求
     */
    cancelAllRequest() {
        for (const [, controller] of this.abortControllerMap) {
            controller.abort();
        }
        this.abortControllerMap.clear();
    }

    /**
     * 取消指定的请求
     * 并发上传文件的url通常是一样的通过url取消请求会取消所有上传操作故此方法不宜用来取消上传请求
     * @param url 待取消的请求URL
     */
    cancelRequest(url: string | string[]) {
        const urlList = Array.isArray(url) ? url : [url];
        urlList.forEach(_url => {
            this.abortControllerMap.get(_url)?.abort();
            this.abortControllerMap.delete(_url);
        });
    }
}
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6