携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情
设计思路:
本来这块的逻辑不多,都在应用管理器AppLoader里面写着,因为应用管理器中有关于接口服务注册和监听相关,最后做的东西会越来越多,面临如下问题:
业务不断扩展,对接口请求拦截部分要求也越来越高,
有了拆出来的想法,而且后期要做埋点支持,也可以在这个里面去做。
设计实践:
大体的流程是这样。还是比较复杂的。
从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