构建 Vue 全局错误处理体系,实现业务与错误解耦
探讨了 Vue 项目中全局错误处理的必要性与设计方法。首先阐述了将业务逻辑与错误处理解耦以及为监控提供统一入口的重要性。接着介绍了 Vue 3 中 app.config.errorHandler 的基础用法及其捕获范围。进阶部分提出了定义可识别业务错误基类、在 errorHandler 中进行分类处理、补齐 Promise reject 捕获能力以及采用策略模式封装错误处理策略的方案。最终目标是提升项目的可维护性和长期稳定性。

探讨了 Vue 项目中全局错误处理的必要性与设计方法。首先阐述了将业务逻辑与错误处理解耦以及为监控提供统一入口的重要性。接着介绍了 Vue 3 中 app.config.errorHandler 的基础用法及其捕获范围。进阶部分提出了定义可识别业务错误基类、在 errorHandler 中进行分类处理、补齐 Promise reject 捕获能力以及采用策略模式封装错误处理策略的方案。最终目标是提升项目的可维护性和长期稳定性。

在之前的实践中,曾分享过替代传统 try-catch 的链式调用封装思路,以及网络层面的 Axios 错误处理封装方案。但这些方案多局限于特定场景,难以完全满足生产环境下的项目需求。因此,构建一套全局错误处理机制显得尤为重要。

在业务模块中,我们真正关心的是数据是否可用,以及页面状态如何变化,并不关心网络异常的类型、提示和跳转。所以需要将错误策略抽离到全局层,让业务代码只专注于处理业务,全局错误处理层专注于处理各类错误,解耦后业务层和全局错误层都更加纯粹,也更有利于长期维护和拓展。
项目上线后,对于错误信息除了要建立临时应对和处理机制外,还需要定时收集和上报,给错误分级,还要收集用户的环境信息,这样才能给开发者提供准确的数据信息,从而针对性的修复 bug 以及性能优化。
在 Vue 3 中,官方提供了一个明确的入口:app.config.errorHandler。在 main.js 中,添加如下代码即可:
const app = createApp(App)
app.config.errorHandler = (err, instance, info) => {
console.error(err)
}
app.config.errorHandler 只会捕获 Vue 运行时上下文中的错误,包括:
不在上述范围内,脱离了 Vue 的响应式调度体系的错误均不会被捕获,比如:
setTimeout(() => {
throw new Error('timeout error') // 不会捕获
})
fetch('/api').then(() => {
throw new Error('fetch error') // 不会捕获
})
所以 Promise 的 reject 并不会天然进全局错误处理,后面进阶方案里会解决这个问题。
Vue 3 中的定义如下:
app.config.errorHandler = ( err: unknown, instance: ComponentPublicInstance | null, info: string ) => void
三个参数的具体意义为:
app.config.errorHandler = (err, instance, info) => {
console.log(err) // 实际抛出的错误对象
console.log(instance) // 出错的组件实例(可能为 null)
console.log(info) // 错误来源描述(字符串)
}
真正的工程实践中,我们关心错误是为了解决错误,所以需要对业务错误进行鉴别分类。
首先需要定义可识别的业务错误基类及其派生类,比如:
export class BusinessError extends Error {
constructor(message, code) {
super(message)
this.code = code
this.isBusinessError = true
}
}
export class AuthError extends BusinessError {
constructor(message = '登录已失效') {
super(message, 'AUTH_ERROR')
}
}
export class PermissionError extends BusinessError {
constructor(message = '没有操作权限') {
super(message, 'PERMISSION_ERROR')
}
}
在具体的业务代码中,遇到错误时,就使用对应的错误类实例化并抛出,app.config.errorHandler 就会捕获到这个错误实例,比如:
if (!token) {
throw new AuthError()
}
现在,在定义了可识别的业务错误之后,全局错误处理的优势就体现出来了,此时业务错误类型可控,有基础应对手段,并且还有错误上报策略 reportError 以应对突发情况:
app.config.errorHandler = (err, instance, info) => {
if (err instanceof BusinessError) {
handleBusinessError(err)
return
}
handleUnknownError(err, instance, info)
}
export function handleBusinessError(err) {
ElMessage.warning(err.message)
if (err.code === 'AUTH_ERROR') {
router.push('/login')
}
}
export function handleUnknownError(err, instance, info) {
ElMessage.error('系统异常,请稍后再试')
reportError({ err, component: instance?.type?.name, info, })
}
export function reportError({ err, component, info }) {
const payload = {
message: err.message,
stack: err.stack,
component,
info,
ua: navigator.userAgent,
time: Date.now(),
}
fetch('/error/report', {
method: 'POST',
body: JSON.stringify(payload),
})
}
reportError 方法收集了错误的类型、信息、位置、发生时间,客户端的类型、操作系统、浏览器版本等信息,集中上报等待解决。
前面说过,errorHandler 不会自动捕获所有 Promise 的 reject,工程中常见解决方案是在请求层统一转抛错误,这就回到了文章开头时我们提到的在网络层面实现数据与状态解耦的 Axios 错误处理封装方案,由于那篇博文已经详细介绍过了,这里只给个简要的例子:
axios.interceptors.response.use(
res => res,
err => {
throw err // 重新抛给 Vue
}
)
这样就能保证所有异常最终都会汇聚到一个出口。
看到这个词有些粉丝可能会有印象,以前的博文也提到过策略表模式,在全局错误处理中依然好用,这样就不用在 errorHandler 里写一堆 if else 了,更容易拓展和维护,比如:
app.config.errorHandler = (err) => {
const handler = errorStrategyMap[err.code] || errorStrategyMap.default
handler(err)
}
const errorStrategyMap = {
AUTH_EXPIRED: (err) => {
ElMessage.error(err.message)
router.push('/login')
},
default: (err) => {
ElMessage.error('系统异常')
reportError(err)
}
}
通过进阶的全局错误处理设计,将业务逻辑与错误处理解耦,不仅能让页面代码更加清晰简洁,还能实现错误的分级处理,从而显著提升项目在生产环境中的可维护性和长期稳定性。
只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online