在整个http的链路中,异常错误对前端来说尤为重要,他作用在很多不同的场景,通用的比如500, 502等; 一个好的软件通常需要在不同的错误场景中做不同的事情。当用户cookie失效时,希望能自动跳转到登录页;当用户权限发生变更时,希望能跳转到一个友好的提示页;那么如何满足这些个性化的诉求呢?接下来让我们一起了解oinone前端网络请求-拦截器。
一、入口
在src目录下main.ts中可以看到VueOioProvider,这是系统功能提供者的注册入口
import interceptor from './middleware/network-interceptor';
VueOioProvider(
{
http: {
callback: interceptor
}
},
[]
);
二、middleware
在项目初始化时使用CLI构建初始化前端工程,在src/middleware有拦截器的默认实现:
三、interceptor
interceptor在请求返回后触发,interceptor有两个回调函数,error和next
error参数
-
graphQLErrors 处理业务异常
-
networkError 处理网络异常
next
- extensions 后端返回扩展参数
const interceptor: RequestHandler = (operation, forward) => {
return forward(operation).subscribe({
error: ({ graphQLErrors, networkError }) => {
console.log(graphQLErrors, networkError);
// 默认实现 => interceptor error
},
next: ({ extensions }) => {
console.log(extensions);
// 默认实现 => interceptor next
},
});
};
四、interceptor error
// 定义错误提示等级
const DEFAULT_MESSAGE_LEVEL = ILevel.ERROR;
// 错误提示等级 对应提示的报错
const MESSAGE_LEVEL_MAP = {
[ILevel.ERROR]: [ILevel.ERROR],
[ILevel.WARN]: [ILevel.ERROR, ILevel.WARN],
[ILevel.INFO]: [ILevel.ERROR, ILevel.WARN, ILevel.INFO],
[ILevel.SUCCESS]: [ILevel.ERROR, ILevel.WARN, ILevel.INFO, ILevel.SUCCESS],
[ILevel.DEBUG]: [ILevel.ERROR, ILevel.WARN, ILevel.INFO, ILevel.SUCCESS, ILevel.DEBUG]
};
// 错误提示通用函数
const notificationMsg = (type: string = 'error', tip: string = '错误', desc: string = '') => {
notification[type]({
message: tip,
description: desc
});
};
// 根据错误等级 返回错误提示和类型
const getMsgInfoByLevel = (level: ILevel) => {
let notificationType = 'info';
let notificationText = translate('kunlun.common.info');
switch (level) {
case ILevel.DEBUG:
notificationType = 'info';
notificationText = translate('kunlun.common.debug');
break;
case ILevel.INFO:
notificationType = 'info';
notificationText = translate('kunlun.common.info');
break;
case ILevel.SUCCESS:
notificationType = 'success';
notificationText = translate('kunlun.common.success');
break;
case ILevel.WARN:
notificationType = 'warning';
notificationText = translate('kunlun.common.warning');
break;
}
return {
notificationType,
notificationText
};
};
error: ({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(async ({ message, locations, path, extensions }) => {
let { errorCode, errorMessage, messages } = extensions || {};
// FIXME: extensions.errorCode
if (errorCode == null) {
const codeArr = /code: (\d+),/.exec(message);
if (codeArr) {
errorCode = Number(codeArr[1]);
}
}
if (errorMessage == null) {
const messageArr = /msg: (.*),/.exec(message);
if (messageArr) {
errorMessage = messageArr[1];
}
}
// 错误通用提示
if (messages && messages.length) {
messages.forEach((m) => {
notificationMsg('error', translate('kunlun.common.error'), m.message || '');
});
} else {
notificationMsg('error', translate('kunlun.common.error'), errorMessage || message);
}
// 提示扩展信息 根据错误等级来提示对应级别的报错
const extMessage = getValue(response, 'extensions.messages');
if (extMessage && extMessage.length) {
const messageLevelArr = MESSAGE_LEVEL_MAP[DEFAULT_MESSAGE_LEVEL];
extMessage.forEach((m) => {
if (messageLevelArr.includes(m.level)) {
const { notificationType, notificationText } = getMsgInfoByLevel(m.level);
notificationMsg(notificationType, notificationText, m.message || '');
}
});
}
// 消息模块的用户未登录错误码
const MAIL_USER_NOT_LOGIN = 20080002;
// 基础模块的用户未登录错误码
const BASE_USER_NOT_LOGIN_ERROR = 11500001;
if (
[MAIL_USER_NOT_LOGIN, BASE_USER_NOT_LOGIN_ERROR].includes(Number(errorCode)) &&
location.pathname !== '/auth/login'
) {
const redirect_url = location.pathname;
location.href = `/login?redirect_url=${redirect_url}`;
}
/**
* 应用配置异常跳转至通用的教程页面
*/
// 模块参数配置未完成
const BASE_SYSTEM_CONFIG_IS_NOT_COMPLETED_ERROR = 11500004;
if ([BASE_SYSTEM_CONFIG_IS_NOT_COMPLETED_ERROR].includes(Number(errorCode))) {
const action = getValue(response, 'extensions.extra.action');
if (action) {
Action.registerAction(action.model, action);
const searchParams: string[] = [];
searchParams.push(`module=${action.module}`);
searchParams.push(`model=${action.model}`);
searchParams.push(`viewType=${action.viewType}`);
searchParams.push(`actionId=${action.id}`);
const href = `${origin}/page;${searchParams.join(';')}`;
location.href = href;
}
}
});
}
if (networkError) {
const { name, result } = networkError;
const errMsg = (result && result.message) || `${networkError}`;
if (name && result && result.message) {
notification.error({
message: translate('kunlun.common.error'),
description: `[${name}]: ${errMsg}`,
});
}
}
}
四、interceptor next
next: ({ extensions }) => {
if (extensions) {
const messages = extensions.messages as {
level: 'SUCCESS';
message: string;
}[];
if (messages)
messages.forEach((msg) => {
notification.success({
message: '操作成功',
description: msg.message,
});
});
}
}
六、完整代码
import { NextLink, Operation } from 'apollo-link';
import { notification } from 'ant-design-vue';
import getValue from 'lodash/get';
import { Action, ILevel, translate } from '@kunlun/dependencies';
interface RequestHandler {
(operation: Operation, forward: NextLink): Promise<any> | any;
}
const DEFAULT_MESSAGE_LEVEL = ILevel.ERROR;
const MESSAGE_LEVEL_MAP = {
[ILevel.ERROR]: [ILevel.ERROR],
[ILevel.WARN]: [ILevel.ERROR, ILevel.WARN],
[ILevel.INFO]: [ILevel.ERROR, ILevel.WARN, ILevel.INFO],
[ILevel.SUCCESS]: [ILevel.ERROR, ILevel.WARN, ILevel.INFO, ILevel.SUCCESS],
[ILevel.DEBUG]: [ILevel.ERROR, ILevel.WARN, ILevel.INFO, ILevel.SUCCESS, ILevel.DEBUG]
};
const notificationMsg = (type: string = 'error', tip: string = '错误', desc: string = '') => {
notification[type]({
message: tip,
description: desc
});
};
const getMsgInfoByLevel = (level: ILevel) => {
let notificationType = 'info';
let notificationText = translate('kunlun.common.info');
switch (level) {
case ILevel.DEBUG:
notificationType = 'info';
notificationText = translate('kunlun.common.debug');
break;
case ILevel.INFO:
notificationType = 'info';
notificationText = translate('kunlun.common.info');
break;
case ILevel.SUCCESS:
notificationType = 'success';
notificationText = translate('kunlun.common.success');
break;
case ILevel.WARN:
notificationType = 'warning';
notificationText = translate('kunlun.common.warning');
break;
}
return {
notificationType,
notificationText
};
};
const interceptor: RequestHandler = (operation, forward) => {
return forward(operation).subscribe({
error: ({ graphQLErrors, networkError, response }) => {
if (graphQLErrors) {
graphQLErrors.forEach(async ({ message, locations, path, extensions }) => {
let { errorCode, errorMessage, messages } = extensions || {};
// FIXME: extensions.errorCode
if (errorCode == null) {
const codeArr = /code: (\d+),/.exec(message);
if (codeArr) {
errorCode = Number(codeArr[1]);
}
}
if (errorMessage == null) {
const messageArr = /msg: (.*),/.exec(message);
if (messageArr) {
errorMessage = messageArr[1];
}
}
if (messages && messages.length) {
messages.forEach((m) => {
notificationMsg('error', translate('kunlun.common.error') || '', m.message || '');
});
} else {
notificationMsg('error', translate('kunlun.common.error') || '', errorMessage || message);
}
const extMessage = getValue(response, 'extensions.messages');
if (extMessage && extMessage.length) {
const messageLevelArr = MESSAGE_LEVEL_MAP[DEFAULT_MESSAGE_LEVEL];
extMessage.forEach((m) => {
if (messageLevelArr.includes(m.level)) {
const { notificationType, notificationText } = getMsgInfoByLevel(m.level);
notificationMsg(notificationType, notificationText, m.message || '');
}
});
}
console.log(extMessage);
// 消息模块的用户未登录错误码
const MAIL_USER_NOT_LOGIN = 20080002;
// 基础模块的用户未登录错误码
const BASE_USER_NOT_LOGIN_ERROR = 11500001;
if (
[MAIL_USER_NOT_LOGIN, BASE_USER_NOT_LOGIN_ERROR].includes(Number(errorCode)) &&
location.pathname !== '/auth/login'
) {
const redirect_url = location.pathname;
location.href = `/login?redirect_url=${redirect_url}`;
}
/**
* 应用配置异常跳转至通用的教程页面
*/
// 模块参数配置未完成
const BASE_SYSTEM_CONFIG_IS_NOT_COMPLETED_ERROR = 11500004;
if ([BASE_SYSTEM_CONFIG_IS_NOT_COMPLETED_ERROR].includes(Number(errorCode))) {
const action = getValue(response, 'extensions.extra.action');
if (action) {
Action.registerAction(action.model, action);
const searchParams: string[] = [];
searchParams.push(`module=${action.module}`);
searchParams.push(`model=${action.model}`);
searchParams.push(`viewType=${action.viewType}`);
searchParams.push(`actionId=${action.id}`);
const href = `${origin}/page;${searchParams.join(';')}`;
location.href = href;
}
}
});
}
if (networkError) {
const { name, result } = networkError;
const errMsg = (result && result.message) || `${networkError}`;
if (name && result && result.message) {
notification.error({
message: translate('kunlun.common.error') || '',
description: `[${name}]: ${errMsg}`
});
}
}
}
});
};
export default interceptor;
Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9307.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验