refactor(http, diy): 抽象通用网络错误处理逻辑
1. 抽离通用http错误分类器到单独模块,实现错误处理复用 2. 统一多语言文案,将diy专属错误合并到通用http命名空间 3. 简化diy页面的错误处理代码,降低维护成本
This commit is contained in:
101
common/js/http-error.js
Normal file
101
common/js/http-error.js
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 通用网络/接口错误分类器
|
||||
*
|
||||
* 适用场景:
|
||||
* - uniapp 各端统一错误分类(diy.js / 商品 / 订单 / 自定义页面等)
|
||||
* - 任意传入 {statusCode, errMsg, message} 形式错误对象的位置
|
||||
*
|
||||
* 设计要点:
|
||||
* 1) 与 Vue / $lang 解耦:不调用任何 i18n 函数,只返回分类结果 + 原始错误字段
|
||||
* 调用方拿到 type 后,自行决定使用 $lang('http.timeout') / $lang('http.serverError')
|
||||
* 或其它命名空间的文案,完全保持各模块原有的 key 命名习惯
|
||||
* 2) 通用网络/接口错误统一映射到 common.http.* 命名空间:
|
||||
* - http.networkError: 通用网络异常(兜底)
|
||||
* - http.timeout: 请求超时
|
||||
* - http.serverError: 服务器错误(5xx)
|
||||
* - http.notFound: 接口不存在(404)
|
||||
* - http.auth: 无访问权限(401/403)
|
||||
* - http.unknown: 其他非 2xx
|
||||
* 3) 兼容多种错误对象形态:
|
||||
* - uniapp request: { statusCode, errMsg, data }
|
||||
* - axios: { response: { status }, message }
|
||||
* - fetch / 原生: { message, name }
|
||||
*
|
||||
* @param {Object|string} err 错误对象或后端业务消息字符串
|
||||
* @returns {{ type: string, statusCode?: number, errMsg?: string, raw?: any }}
|
||||
* - type 取值:
|
||||
* 'business' - 后端返回的业务消息字符串(已透传到 raw)
|
||||
* 'empty' - 错误对象为空
|
||||
* 'notFound' - HTTP 404
|
||||
* 'server' - HTTP 5xx
|
||||
* 'auth' - HTTP 401 / 403
|
||||
* 'request' - 其它非 2xx 状态码
|
||||
* 'timeout' - errMsg 含 timeout
|
||||
* 'network' - errMsg 含 connect / network / fail
|
||||
* 'unknown' - 无法分类
|
||||
* - statusCode: 若有则原样返回
|
||||
* - errMsg: 归一后的原始消息
|
||||
* - raw: 原始输入,方便调用方进一步处理
|
||||
*/
|
||||
export function classifyHttpError(err) {
|
||||
// 1) 无错误对象
|
||||
if (!err) {
|
||||
return { type: 'empty', raw: err };
|
||||
}
|
||||
|
||||
// 2) 后端直接返回的业务消息(字符串)
|
||||
if (typeof err === 'string') {
|
||||
return { type: 'business', raw: err };
|
||||
}
|
||||
|
||||
// 3) 字段归一(兼容 uni / axios / 原生 Error)
|
||||
const statusCode = err.statusCode
|
||||
?? err.response?.status
|
||||
?? err.status;
|
||||
const errMsg = err.errMsg || err.message || '';
|
||||
|
||||
if (statusCode) {
|
||||
if (statusCode === 404) return { type: 'notFound', statusCode, errMsg, raw: err };
|
||||
if (statusCode >= 500) return { type: 'server', statusCode, errMsg, raw: err };
|
||||
if (statusCode === 401 || statusCode === 403) return { type: 'auth', statusCode, errMsg, raw: err };
|
||||
return { type: 'request', statusCode, errMsg, raw: err };
|
||||
}
|
||||
|
||||
if (/timeout/i.test(errMsg)) {
|
||||
return { type: 'timeout', errMsg, raw: err };
|
||||
}
|
||||
if (/(connect|network|fail)/i.test(errMsg)) {
|
||||
return { type: 'network', errMsg, raw: err };
|
||||
}
|
||||
|
||||
return { type: 'unknown', errMsg, raw: err };
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 classifyHttpError 的结果,映射到 common.http.* 命名空间的 i18n key
|
||||
*
|
||||
* 通用网络/接口错误统一走 http.*,调用方通过 $lang(key) 解析文案。
|
||||
* 原 diy.errTimeout 这类 key 已合并到 http.*,保持项目国际化更专业。
|
||||
*
|
||||
* @param {string} type classifyHttpError 返回的 type
|
||||
* @returns {string|null} 对应的 http.* key;type='business' 时返回 null(透传 raw)
|
||||
*/
|
||||
export function httpErrorKey(type) {
|
||||
switch (type) {
|
||||
case 'empty': return 'http.networkError';
|
||||
case 'business': return null; // 透传,不用 key
|
||||
case 'notFound': return 'http.notFound';
|
||||
case 'server': return 'http.serverError';
|
||||
case 'auth': return 'http.auth';
|
||||
case 'request': return 'http.unknown';
|
||||
case 'timeout': return 'http.timeout';
|
||||
case 'network': return 'http.networkError';
|
||||
case 'unknown':
|
||||
default: return 'http.networkError';
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
classifyHttpError,
|
||||
httpErrorKey,
|
||||
};
|
||||
Reference in New Issue
Block a user