业务侧-异常拦截管理器-ErrorLoader

109 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情

设计思路:

本来这块的逻辑不多,都在应用管理器AppLoader里面写着,因为应用管理器中有关于接口服务注册和监听相关,最后做的东西会越来越多,面临如下问题:

业务不断扩展,对接口请求拦截部分要求也越来越高,

有了拆出来的想法,而且后期要做埋点支持,也可以在这个里面去做。

设计实践:

image.png

大体的流程是这样。还是比较复杂的。

从AppLoader可以看出来,目前Loader层,只是进行了接口注册。

ErrorLoader

/**
*  接口注册
* @param {*} No
* 场景: 系统加载
*/
function registerError() {
    // 系统异常监听--拦截
    Service.onErrorStatus((err) => {
        console.error(err)
        interceptRedirectError(err) || httpErrorStatus(err)
    })
}

主要是使用了 Service.onErrorStatus错误异常监听,如果系统的请求以及主动推送的错误,回调函数会进行执行,从而异常逻辑处理

/**
 * 拦截需要跳转页面的错误--会话失效--重新登录等
 * @param {*} error 
 */
function interceptRedirectError(error) {
    let isRedirect = false
    const cError = CONFIG.ERROR_RES_CONST.find((item) => item.code == error.code)
    if (!cError) return isRedirect

    EduMessageBox.close()
    EduMessageBox.alert(cError.label, '系统提示', {
        confirmButtonText: '重新登录',
        showCancelButton: true,
        cancelButtonText: '取消',
        type: 'warning',
        callback: async (action) => {
            if (action === 'confirm') LoginLoader.redirect()
        },
    })
    isRedirect = true

    return isRedirect
}

提醒,选择重新登录

我们深入挖掘一下,找一下 onErrorStatus

  onErrorStatus(featureUpdate) {
    const fn = (res) => featureUpdate(res);
    SocketEmitter.on(this.REQ_EMIT, fn)
  }
httpRequest.then(()=>{...}).cath(err=>{
  ....
  SocketEmitter.emit(this.REQ_EMIT, err)
})

使用到了,SocketEmitter.on(this.REQ_EMIT, fn)进行订阅, 代码主要是在框架层,

httpRequest完成后,异常情况处理,会执行 SocketEmitter.emit(this.REQ_EMIT, err),发送异常消息

ErrorLoader调用框架层提供的异常回调方法即可,不用关注内部使用订阅发布机制还是其他方式,实现方式内部封装。

完整代码如下

/*
 * @description: 系统异常管理器
 * @Author: ffzhengc
 */

import { Service } from '@basic-library'
import CONFIG from '@/common/config'
import { EduMessageBox, EduMessage } from '@components'
import LoginLoader from "./Login";

/**
 * 处理异常
 * @param {*} error 
 */
function findHttpError(error) {
    let message = '';
    if (error) {
        switch (error.status) {
            case 302: message = '接口重定向了!'; break;
            case 400: message = '参数不正确!'; break;
            case 401: message = '您未登录,或者登录已经超时,请先登录!'; break;
            case 403: message = '您没有权限操作!'; break;
            case 404: message = `请求地址出错: ${error.config.url}`; break; // 在正确域名下
            case 408: message = '请求超时!'; break;
            case 409: message = '系统已存在相同数据!'; break;
            case 500: message = '服务器内部错误!'; break;
            case 501: message = '服务未实现!'; break;
            case 502: message = '网关错误!'; break;
            case 503: message = '服务不可用!'; break;
            case 504: message = '服务暂时无法访问,请稍后再试!'; break;
            case 505: message = 'HTTP版本不受支持!'; break;
            case 666: message = error.message; break;
            default: message = '异常问题,请联系管理员!'; break
        }
    }

    return message
}

/**
 * 拦截需要跳转页面的错误--会话失效--重新登录等
 * @param {*} error 
 */
function interceptRedirectError(error) {
    let isRedirect = false
    const cError = CONFIG.ERROR_RES_CONST.find((item) => item.code == error.code)
    if (!cError) return isRedirect

    EduMessageBox.close()
    EduMessageBox.alert(cError.label, '系统提示', {
        confirmButtonText: '重新登录',
        showCancelButton: true,
        cancelButtonText: '取消',
        type: 'warning',
        callback: async (action) => {
            if (action === 'confirm') LoginLoader.redirect()
        },
    })
    isRedirect = true

    return isRedirect
}

/**
 * 正常错误拦截
 * @param {*} error 
 */
function httpErrorStatus(error) {
    const errorMessage = findHttpError(error)
    EduMessage({
        type: 'error',
        message: errorMessage
    })
}

/**
*  接口注册
* @param {*} No
* 场景: 系统加载
*/
function registerError() {
    // 系统异常监听--拦截
    Service.onErrorStatus((err) => {
        console.error(err)
        interceptRedirectError(err) || httpErrorStatus(err)
    })
}

export default {
    registerError
}

封装完毕~~这章相对来说,逻辑部分不多。后期有埋点需要会进入其中...

针对Loader管理器的一系列,请看下方:

业务侧-Loader设计
业务侧-系统应用加载器-AppLoader
业务侧-登录管理器-LoginLoader
业务侧-异常拦截管理器-ErrorLoader