• home > webfront > ECMAS > vue >

    axios封装:vue项目中axios发起的ajax请求错误统一处理

    Author:zhoulujun Date:

    是先走拦截器,再走业务代码,如何由业务代码决定是否隐藏统一错误提示呢?

    之前写过《再谈from属性EncType与axios封装—axios拦截与中断—源码浅析》,对于里面的错误处理不够理想,目前找到一些解决方案


    通过配置config来分流处理逻辑

    就是通过axios config参数,在拦截器里面通过 配置,来处理全局逻辑(需要增加全局配置)。

    一下引用是 来自:《axios 的错误处理 https://godruoyi.com/posts/axios-error-handling

    但 axios 提供的 response 拦截器是全局的

    axios.interceptors.response.use(function (response) {
        return response;
    }, function (error) {
        // 如4xx/5xx等基本错误的处理
        alert('全局错误处理')
    
        return Promise.reject(error); 
    });

    若我们想对某个具体请求进行错误处理时,情况就稍微有点复杂了,比如:

    axios.interceptors.response.use(function (response) {
        return response;
    }, function (error) {
        if (error.response.status == 429) {
            if (error.response.data.error_code == 4291011) {
                // 单独处理投票错误
            } else if (error.response.data.error_code == 4291011) {
    				    // 作品票数异常,需先通过滑动验证码
    				}
        }
    
        // 处理其他 如4xx/5xx等基本错误的处理
        return Promise.reject(error); 
    });


    但是这样做却存在很多问题

    • 随着各种错误码的增多,拦截器需要处理的情况越来越多,最终充满着大量的 if-else

    • 具体的错误码应该和具体发起请求的代码放在一起,一来方便查看,二来好扩展及定位

    所以我们可以把错误处理逻辑移到调用代码处,如下:

    axios.post('/vote/1').then(function (response) {
        // success
    }).catch(function (error) {
        let code = error.response.data.error_code
        if (code == 4291011) {
            alert('投票超限')
        } elseif (code == 4030001) {
            alert('作品票数异常,需先通过滑动验证码')
        }
    });

    但这样又存在一个问题,由于 axios 拦截器的代码会比 catch 先执行,所以当执行到 catch 时,实际上 response 拦截器的代码已全部执行完成,所以会先后弹出「全局错误处理」-> 「投票超限」。

    axios config 

    axios.interceptors.response.use(function (response) {
        return response;
    }, function (error) {
        error.globalErrorProcess = function () {
            switch (this.response.status) {
                case 401: // 处理基本 401 错误
                    break;
                case 404: // 处理基本 404 错误
                    break;
                case 403: // 处理基本 403 错误
                    break;
                          // 处理其他4xx/5xx等基本错误的处理
            }
    
            return Promise.reject(this);
        };
    
        if(error.config.hasOwnProperty('catch') && error.config.catch == true) {
            return Promise.reject(error);
        }
    
        return error.globalErrorProcess()
    });

    我们定义一个全局的错误处理器,并把他赋给 error 对象的 globalErrorProcess 方法。接着判断当前请求 config 是否启用 catch,若启用,默认不进行任何错误处理,交由调用方自行负责;否则用全局错误处理。

    在使用时,若需要自定义捕获错误,可显示传递一个 config,相应请求方法的 API 如下:

    • axios.request(config)

    • axios.get(url[, config])

    • axios.delete(url[, config])

    • axios.head(url[, config])

    • axios.options(url[, config])

    • axios.post(url[, data[, config]])

    • axios.put(url[, data[, config]])

    • axios.patch(url[, data[, config]])

    这方案时比较常见的方案,但是不想修改config

    业务代码决定是否隐藏统一错误提示

    这个方案来自:

    将统一的错误提示使用setTimeout放到下一个loop执行

    request.interceptors.response.use(
        (response) => response.data,
        (error) => {
            ...
            let isShowNormalError = true
            const hideNormalError = () => isShowNormalError = false
    
            setTimeout(() => {
                if (isShowNormalError) {
                    Message.error(msg)
                }
            })
    
            return Promise.reject({ ...error.response, hideNormalMessage }) // 在error.response上添加方法
        }
    )

    业务代码:

    someAPIFN()
        .then()
        .catch({ data, hideNormalMessage }) {
            // 业务代码
            hideNormalMessage()
        }

    这个解决方案的关键在于使用setTimeout使得统一错误处理“落后”于业务代码,并在Promise.reject的参数中添加控制函数使得业务代码可以决定是否展示统一错误处理。稍作抽象与封装就可以形成一个业务无关、框架无关的统一错误处理方案。

    这个方案也还是不太满意





    转载本站文章《axios封装:vue项目中axios发起的ajax请求错误统一处理》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8751.html