ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Vue全局错误处理体系:从重复try/catch到统一捕获上报的完整实践

Vue全局错误处理体系:从重复try/catch到统一捕获上报的完整实践 接手过一个老项目里面所有try/catch密密麻麻每个组件都有一套自己的错误提示逻辑接口一挂就弹一个alert后端报错和前端报错混在一起根本分不清是谁的问题。最要命的是线上用户遇到白屏时我们啥都查不到只能靠用户截图。当时我脑子里只有一个想法Vue项目怎么老是在重复处理异常为什么不能有一套机制把所有错误统一收口、按规则分类、自动上报这篇文章就是我当时踩完坑之后的完整复盘把全局错误处理体系从原理到落地一次讲清楚。如果你正在做 Vue 项目不管是用 Vue 2 还是 Vue 3不管项目大小只要你发现自己或团队成员每隔几天就要写一段差不多的错误处理代码那这篇文章就是写给你的。我能帮你做三件事解释清楚为什么你总在重复处理异常拆解一个完整的全局错误处理体系该由哪几层组成给出可以直接抄进项目的完整代码方案和背后的设计理由。1. 重复处理异常的病根每个组件都在单打独斗先别急着写代码我们先分析一下重复处理异常这个现象是怎么来的。很多人项目一开始很小一个页面从接口拿数据try/catch写在async函数里弹个提示就完事了。页面多了之后每个页面都复制这一套逻辑。慢慢你会发现代码里到处是重复的catch块而且处理方式各不相同。这不是偶然而是错误处理缺乏全局设计导致的必然结果。1.1 分散式错误处理的典型表现我在代码审查里见到的分散式错误处理基本是这几种画风第一每个组件各自弹提示。组件 A 报错弹alert组件 B 报错用message.error组件 C 干脆只console.log用户完全感知不到。第二接口层和 UI 层职责混乱。有的团队喜欢在axios拦截器里统一弹提示有的喜欢在页面里一个个判断res.code ! 0两边各弹一次用户能看到两个错误弹窗。第三关键错误没有上报。console.log打在浏览器控制台里线上环境用户根本不会打开控制台错误信息等于丢失了。这背后有个核心问题没有把错误捕获和错误处理分开。捕获是技术动作应该由全局机制负责处理是业务策略应该由统一入口负责。两者一旦混在组件里每个组件都会按自己的心情去决定怎么处理错误结果就是既不统一也不完整。1.2 分散处理带来的隐性成本很多人觉得无非就是多写几行catch又不是不能用。其实隐性成本比想象中高得多。先看维护成本。假设接口错误提示需要从网络错误改成网络开小差了请稍后重试如果你有 20 个页面各自处理错误就得改 20 处漏改一处用户看到的就是两种不同的提示风格非常不专业。再看排查成本。线上用户报障说下单失败但提示框里只写了操作失败四个字没有任何上下文信息。你查日志根本查不到用户当时在哪个页面、调用了哪个接口、后端返回了什么。分散式的错误处理里,往往只有简单提示没有埋点也没有上报出了问题全靠猜。最后是稳定性风险。有些组件里直接写了window.location.href或刷新页面之类的粗暴处理一旦误判错误类型会把一个可以恢复的临时故障变成用户数据丢失的严重事故。我见过一个表单页面因为接口返回 500 就直接清空所有表单数据导致用户填报十分钟的内容全没了。1.3 全局错误处理体系的本质是什么前面说了这么多痛点那全局错误处理体系到底是什么用一句话概括它是把捕获错误、分类错误、决策处理、反馈用户、上报记录这五个环节从组件代码里抽离出来收口到独立的模块里统一完成的一套机制。这个体系至少要覆盖四类错误来源错误来源典型场景捕获位置Vue 组件生命周期/渲染模板里访问不存在的属性、计算属性抛异常VueerrorCaptured/errorHandler全局 JS 运行时错误第三方脚本报错、未捕获的同步异常window.onerrorPromise 异步错误接口返回 reject、异步函数里未 catch 的异常unhandledrejection资源加载错误图片、CDN 脚本加载失败error事件的捕获阶段只要这四个来源全都能被拦截到错误就相当于被一网打尽了组件里根本不需要再写重复的catch。2. Vue 的错误捕获机制拆解你能用的都有哪些在动手搭建体系之前必须先把 Vue 给我们提供的错误捕获机制一个个弄明白。它们的适用范围、触发时机、调用优先级各不相同用错了等于白做。2.1 Vue 2 的 errorHandler 与 errorCapturedVue 2 里Vue.config.errorHandler是一个全局函数任何发生在 Vue 组件渲染、生命周期钩子、事件处理器中的未被捕获错误都会进到这个函数里。它接收三个参数err错误对象、vm组件实例、info错误来源的字符串描述比如render、created、mounted等。Vue 2 的errorCaptured是组件级别的方法用于捕获来自子孙组件的错误。它的特点是一旦错误被某个组件的errorCaptured捕获如果这个函数又返回了false就会阻止这个错误继续向上传播也不会冒泡到全局的errorHandler。这可以用于本地吞掉某些预料内的错误但要小心用滥用会导致错误被静默丢弃。Vue 2 有个容易踩的坑errorHandler默认不会捕获async/await中Promise内部的错误。因为async/await的错误本质上是 Promise 的 reject不会主动抛给 Vue 的运行机制。如果你在mounted里写await this.getData()且getData内部 reject 了这个错误可能只会变成浏览器的unhandledrejection而不是进入errorHandler。2.2 Vue 3 的 app.config.errorHandler 与 errorCapturedVue 3 在 API 上做了调整。全局错误处理通过app.config.errorHandler配置不再依赖Vue.config。同时新增了一个有用的信息errorCaptured可以返回true或false来控制错误是否继续向外传播这在 Vue 2 中只能通过返回false停止传播语义更明确了。Vue 3 官方文档推荐在errorHandler里做三件事把错误信息发给错误追踪服务把组件树链路一起上报让错误在开发环境显示更详细的信息。另外 Vite 在开发模式下有个特点Vue 报错会叠加显示多处堆栈。比如模板编译错误和运行时错误会在控制台里连续输出几段 stack看似混乱但其实每段都代表一层上下文——模板编译信息、组件链路、原生 JS 栈。理解这一点排查报错时就不会被一堆日志吓到。2.3 window.onerror、unhandledrejection 与 Vue 机制的关系window.onerror负责捕获不在 Vue 管控范围内的全局 JS 错误比如第三方 SDK 内部抛出的异常、外部脚本的语法错误等。它的一个限制是无法获得具体错误堆栈只有错误信息文本要拿到更完整的原始信息需要用window.addEventListener(error, handler)事件对象里能拿到message、filename、lineno、colno、error等字段。unhandledrejection负责捕获 Promise 中未能处理的 reject。async/await里如果忘记try/catch往往最终也是在这个事件里兜底。注意一旦某个 Promise 同时被 Vue 的errorHandler处理了不会再触发unhandledrejection因为 Vue 在内部避免重复处理但unhandledrejection发生后如果我们在代码里补了catch让它变成 handled浏览器就不会再触发默认的 console 警告。Vue 的错误处理和浏览器原生错误处理之间存在优先级和覆盖关系Vue 渲染、生命周期内的错误优先进入errorCaptured若没有组件级拦截则进入全局errorHandler。Vue 事件处理器里的错误同样进入errorCaptured/errorHandler。Promise 异步里未捕获的错误可能进入 Vue 机制如果是在组件方法里触发的也可能变成unhandledrejection。纯原生 JS 错误只进window.onerror/error事件。了解这些关系之后我们才能设计一个一个都不能漏的捕获矩阵。3. 体系设计从捕获到上报的完整链路现在到了核心环节。全局错误处理体系不是只有一个errorHandler它是一整套链路。我把它拆成四个层接入层、分发层、策略层、上报层。每一层职责单一层与层之间通过接口对接这样后续要改任何一个环节不会牵一发动全身。3.1 分层设计为什么要这样拆接入层负责捕获所有可能出现的错误。你在main.js里注册监听器把 Vue 错误、原生 JS 错误、Promise 错误、资源加载错误全部接到同一套内部逻辑里。分发层负责把不同类型的错误路由到对应的处理函数。比如资源加载错误不需要上报完整堆栈接口业务错误需要特殊分类语法错误需要标记为致命等级。分发层做的事就是统一入口按规则派发。策略层负责决策怎么处理这个错误。要不要提示用户提示什么文案是否静默忽略是否重试是否跳转这是业务语义最浓的一层也是整个体系里最值得定制的地方。上报层负责持久化记录错误信息。包括构造上报数据、调用上报接口、缓存失败的上报、防止重复上报。线上监控平台很多如果没有自研监控可以先上报到自己的后端日志接口后续再接 Sentry 或自建系统。用一句话解释为什么这么分层捕获是通用的策略是变化的。如果混在一起每改一个业务规则都要动底层捕获逻辑非常危险。3.2 接入层代码四类监听全部收口在 Vue 3 项目里我会在main.js或独立的error-setup.js文件中完成接入// error-setup.js import { createApp } from vue export function setupGlobalErrorHandling(app) { // 1. Vue 运行时错误 app.config.errorHandler (err, instance, info) { ErrorHandlerDispatcher.dispatch({ type: vue, error: err, instance, info, source: describeComponent(instance) }) } // 2. 全局 JS 错误 window.addEventListener(error, (event) { // 过滤掉资源加载错误它们走下面的专门逻辑 if (event.target ! window event.target ! document) { return } ErrorHandlerDispatcher.dispatch({ type: script, error: event.error || new Error(event.message), message: event.message, filename: event.filename, line: event.lineno, column: event.colno }) }, true) // 3. Promise 错误 window.addEventListener(unhandledrejection, (event) { ErrorHandlerDispatcher.dispatch({ type: promise, error: event.reason, promise: event.promise }) }) // 4. 资源加载错误 window.addEventListener(error, (event) { if (event.target ! window event.target ! document) { ErrorHandlerDispatcher.dispatch({ type: resource, target: event.target, url: event.target.currentSrc || event.target.src, tagName: event.target.tagName }) } }, true) }这段代码里有几个细节要解释error事件用了捕获阶段第三个参数true因为资源加载错误在冒泡阶段默认不会触底到window捕获阶段才能从 DOM 树的各个节点向上拿到所有错误。event.target的过滤逻辑如果是window或document说明是脚本错误如果是img、script等具体元素说明是资源加载错误。两种错误的处理维度完全不同必须分开。ErrorHandlerDispatcher是我自己定义的一个分发器我们马上定义它。3.3 分发层与策略层错误分级和决策机制分发器最核心的功能是错误分类 等级评定。一个错误进来之后我们会根据以下几个维度决定它属于哪一类维度取值示例决策影响错误来源vue / script / promise / resource决定上报格式和堆栈优先级错误类型ReferenceError / TypeError / 业务码 500决定是否提示用户错误等级fatal / error / warning / info决定通知方式和上报紧急度是否已知是否在忽略列表决定是否静默吞掉策略层的核心函数长这样// error-policy.js const IGNORE_ERROR_LIST [ ResizeObserver loop limit exceeded, Script error., ] const FATAL_ERROR_MARKER [ TypeError, ReferenceError, RangeError ] export function decideErrorStrategy(classification) { const { level, message, type: errorType } classification // 1. 已知忽略列表里的错误直接吞掉 for (const ignore of IGNORE_ERROR_LIST) { if (message.includes(ignore)) { return { action: ignore, reason: in-ignore-list } } } // 2. 特定来源的资源加载错误轻量上报 if (errorType resource) { return { action: report-only, level: warning } } // 3. 致命错误提示 上报 if (level fatal) { return { action: report-and-notify, level: fatal } } // 4. 普通错误根据是否影响用户操作决定 return { action: report, level: error } }这里最关键的一步是每个错误最终必须落到一个明确的动作上要么 ignore要么 report要么 notify。绝对不能让一个错误走完整个链路后没有任何结论否则等于没接进来。对用户提示的策略我一般建议这样控制致命错误提示页面开小差了请刷新重试普通接口错误提示后端返回的msg资源加载错误不提示但上报被忽略的错误完全不打扰。提示统一走项目里的 UI 组件比如 Element Plus 的ElMessageNaive UI 的message不要再用alert。3.4 上报层数据结构与容错设计上报是错误处理体系里容易被忽略的一环。很多团队做了捕获、做了提示但没有上报。等于你知道了错误但没有任何记录等于白做。上报数据结构至少要包含这些字段function buildReportPayload(classification) { return { app: your-app-name, env: import.meta.env.MODE, // development / production version: __APP_VERSION__, // 构建版本号 page: window.location.pathname, // 当前路由路径 userId: getCurrentUserId?.() || anonymous, errorType: classification.errorType, errorLevel: classification.level, message: classification.error?.message || classification.message, stack: classification.error?.stack || , component: classification.source || , timestamp: Date.now(), extra: { url: window.location.href, userAgent: navigator.userAgent, routeName: currentRouteName?.() || } } }上报方式优先用sendBeacon因为页面卸载时fetch可能发不出去function report(payload) { try { const blob new Blob([JSON.stringify(payload)], { type: application/json }) navigator.sendBeacon(/api/error-report, blob) } catch (e) { // sendBeacon 不可用时退化为 fetch fetch(/api/error-report, { method: POST, body: JSON.stringify(payload), headers: { Content-Type: application/json } }) } }上报本身必须做容错。如果上报逻辑本身抛异常不能把错误处理体系给拉崩。所以我所有上报函数都会用try/catch包起来宁可丢掉一条上报也不能让它影响主流程。4. 完整落地一套可直接复用的全局错误处理模块讲完设计我们把它整合成一个可以在项目里直接使用的模块。这里我会给出简化版的完整代码并说明关键细节。代码基于 Vue 3 Vite但思想完全适用于 Vue 2 和任何现代前端工程。4.1 目录结构和基础设施我建议把错误处理抽成独立的模块不要挂在utils下的一堆杂函数里。目录结构src/ error/ index.js # 对外暴露 install 和初始化接口 dispatcher.js # 分发器 policy.js # 策略引擎 reporter.js # 上报器 collectors.js # 四种错误来源的接入逻辑error/index.js设计成一个 Vue 插件在main.js里app.use(ErrorPlugin, options)即可。// error/index.js import { setupCollectors } from ./collectors import { createDispatcher } from ./dispatcher const ErrorPlugin { install(app, options {}) { const dispatcher createDispatcher(options) // 接入 Vue 错误源 app.config.errorHandler (err, instance, info) { dispatcher.dispatch({ type: vue, error: err, info, source: getComponentName(instance) }) } // 接入浏览器错误源 setupCollectors((payload) dispatcher.dispatch(payload), options) // 暴露给组件使用的实例方法可选 app.config.globalProperties.$reportError (error, extra {}) { dispatcher.dispatch({ type: manual, error, extra }) } // 挂在 app 上便于组合式 API 使用 app.provide(errorReporter, { report: (error, extra) dispatcher.dispatch({ type: manual, error, extra }), setUserInfo: (info) dispatcher.setUserInfo(info) }) } } export default ErrorPlugingetComponentName的作用是拿到组件链路。Vue 3 的instance上有$options.name、$options.__name或instance.type.name多个字段依次判断能拿到最真实的组件名。组件名对定位错误非常关键没有组件名你只知道某处报错不知道在哪个组件里。4.2 dispatcher 的具体实现dispatcher.js是整个体系的大脑。它接收各种来源的载荷统一标准化为内部对象交给策略引擎决策再按决策结果分发处理。// error/dispatcher.js import { decideErrorStrategy } from ./policy import { report } from ./reporter export function createDispatcher(options) { const userInfo { userId: anonymous } return { setUserInfo(info) { Object.assign(userInfo, info) }, async dispatch(rawPayload) { try { // 归一化把所有来源的错误统一成一个结构 const normalized normalize(rawPayload) // 策略决策 const strategy decideErrorStrategy(normalized) // 执行决策 await executeStrategy(strategy, normalized, options) } catch (e) { // 兜底即使 dispatch 内部报错也不能让页面崩掉 console.error([global-error-system] dispatch failed:, e) } } } } function normalize(raw) { const baseInfo getUserMeta() if (raw.type vue) { return { ...baseInfo, errorType: vue, level: classifyErrorLevel(raw.error), error: raw.error, message: raw.error?.message || raw.info || Unknown Vue error, stack: raw.error?.stack, source: raw.source || , info: raw.info || } } if (raw.type script) { return { ...baseInfo, errorType: script, level: classifyErrorLevel(raw.error), error: raw.error, message: raw.message || raw.error?.message, stack: raw.error?.stack, source: window.onerror } } if (raw.type promise) { return { ...baseInfo, errorType: promise, level: classifyErrorLevel(raw.error), error: raw.error, message: raw.error?.message || Unhandled Promise rejection, stack: raw.error?.stack || } } if (raw.type resource) { return { ...baseInfo, errorType: resource, level: warning, message: Resource load failed: ${raw.url}, source: raw.tagName || unknown } } return { ...baseInfo, errorType: raw.type || manual, level: classifyErrorLevel(raw.error), error: raw.error, message: raw.error?.message || Manual error report, stack: raw.error?.stack || } }executeStrategy的职责是把策略变成具体动作比如控制台打印、UI 提示、上报。async function executeStrategy(strategy, normalized, options) { const { action } strategy // 开发环境始终打印完整错误 if (isDev()) { console.error([Error]:, normalized.message, normalized.stack) } if (action ignore) return if (action report-only) { await report(patchPayload(normalized, options)) return } if (action report-and-notify) { await report(patchPayload(normalized, options)) options.onNotify?.(normalized) // 由业务方传入 UI 提示的回调 return } if (action report) { await report(patchPayload(normalized, options)) } }options.onNotify是业务方传入的回调比如app.use(ErrorPlugin, { onNotify(payload) { if (payload.level fatal) { ElMessageBox.alert(页面开小差了请刷新重试, 系统提示) } else if (payload.message) { ElMessage.error(payload.message) } } })这样把 UI 提示策略从核心逻辑里解耦出来。不允许在 dispatcher 或 reporter 里直接 import 某个 UI 组件库否则后续换 UI 库还得改错误处理模块。4.3 接入代码在入口文件中启用现在在main.js里把整个体系挂上// main.js import { createApp } from vue import App from ./App.vue import router from ./router import ErrorPlugin from ./error import { ElMessage } from element-plus const app createApp(App) app.use(router) app.use(ErrorPlugin, { project: my-project, onNotify(payload) { if (payload.level fatal) { ElMessage.error(系统开小差了请刷新重试) return } if (payload.message) { ElMessage.error(payload.message) } }, // 上报地址留空则只 console 不上报 reportUrl: /api/error-report }) app.mount(#app)这样配置完之后你的 Vue 项目里就基本不需要再写try/catch去做错误提示和上报了。业务代码只需要关心哪些错误需要特殊业务处理其余全部交给全局体系兜底。4.4 业务代码中如何配合使用有了全局体系之后业务代码里不是完全不写try/catch而是写得更有目的性。比如接口调用的数据流转我会这样写async function fetchUserProfile() { try { const user await getUserAPI() state.user user } catch (e) { // 这里只处理业务状态回滚不负责提示用户 state.user null // 即便我们 catch 住了也可以手动上报 reportError(e, { from: fetchUserProfile }) } }配合组合式 API 使用import { inject } from vue const errorReporter inject(errorReporter) function handleSpecialAction() { try { // ...业务逻辑 } catch (e) { errorReporter.report(e, { formData: JSON.stringify(form.value) }) } }但如果你只是调用一个接口await getUserAPI()这个函数内部如果 reject 了那么即使你没有手动 catch它也会被全局的unhandledrejection兜住不会变成静默失败。所以你可以大胆地少写try/catch让全局体系做最后防线。5. 构建完成后的避坑经验这些坑我替你踩过了方案做完了但只有真正上线跑一段时间才知道里面有多少边界要处理。下面这几类坑是我在实际项目中踩过的列出来供参考。5.1 React 之外errorHandler 与 window.onerror 的重复触发问题Vue 3 中某些错误会同时触发app.config.errorHandler和window.addEventListener(error)。比如组件渲染时抛出了一个未处理异常Vue 内部已经捕获并派发给了errorHandler但浏览器的事件机制也可能把它当作一个全局 error event 再触发一次。如果不做去重上报量会翻倍污染监控数据。我的做法是在 dispatcher 里维护一个简单的去重缓存const DEDUP_CACHE new Set() function isDuplicate(error) { const key error?.stack || error?.message || String(error) if (DEDUP_CACHE.has(key)) return true DEDUP_CACHE.add(key) // 只缓存最近 1 分钟的记录防止内存占用过大 setTimeout(() DEDUP_CACHE.delete(key), 60 * 1000) return false }dispatch 函数的最开头先调用isDuplicate如果是重复错误直接丢弃。这个去重逻辑不能只按错误消息去重因为同名错误可能出现在不同组件加stack之后重复率会明显下降。5.2 跨域脚本只有 Script error. 的坑线上项目如果引用了 CDN 上的第三方脚本而且这些脚本没有加crossoriginanonymous属性一旦脚本内部报错浏览器出于安全策略会把错误信息抹成只有一个Script error.。你上报了也等于白报完全不知道发生了什么。解决方案有三个按推荐排序给外部脚本统一加上crossoriginanonymous属性同时确保 CDN 返回正确的Access-Control-Allow-Origin响应头。使用script src... crossoriginanonymous onerror...至少能感知到脚本加载失败。在错误分类时把Script error.标记为warning级别不要当成致命错误避免误报刷屏。这类错误我在开发者工具里看是正常堆栈但线上监控里全是Script error.排查了好久才定位到是跨域资源缺少crossorigin导致的信息丢失。5.3 上报自身的递归保护这是最高优先级的坑。如果上报接口本身报错比如后端 500而在上报逻辑里我们没有做保护那么可能造成两种情况一种是很滑稽的无限循环——错误上报失败触发新的错误新错误再次尝试上报又失败又触发……页面直接被卡死另一种是上报失败产生的错误进入全局捕获然后又走到上报逻辑形成递归。所以上报函数里必须至少做两层保护let reporting false async function report(payload) { if (reporting) return // 防止递归 reporting true try { await fetch(/api/error-report, { ... }) } catch (e) { // 不能再次调用 report console.warn(error report failed:, e) } finally { reporting false } }另外上报逻辑内部永远不要再调用 dispatcher.dispatch否则必然形成循环。这条规矩要作为团队代码评审的检查项。5.4 开发环境和生产环境的差异化处理开发环境里我们希望错误越详细越好控制台打满堆栈甚至直接中断页面生产环境里我们希望错误被捕获后页面继续运行把信息上报即可。两者的策略必须区分。我配置了这样一组规则function isDev() { return import.meta.env.DEV true } function classifyErrorLevel(error) { if (error instanceof TypeError || error instanceof ReferenceError || error instanceof RangeError) { return fatal } return error }开发环境我会额外打印info字段和component字段因为 Vue 的errorHandler中的info在定位模板错误时特别有用。生产环境则不打印这些避免控制台被无意义日志刷爆。5.5 第三方组件的错误边界处理第三方 UI 库内部报错在项目中很常见。比如图表库在数据异常时抛错如果不做隔离整个页面都可能白屏。全局错误体系能兜底但不能阻止白屏发生。更稳妥的做法是用 Vue 3 的内置错误边界Suspense或自定义errorCaptured组件来隔离第三方组件。我在项目里写了一个简单的ErrorBoundary.vuetemplate slot v-if!hasError / div v-else classerror-boundary__fallback 该区域暂时无法显示请刷新重试 /div /template script export default { name: ErrorBoundary, data() { return { hasError: false } }, errorCaptured(err, instance, info) { // 在这里决定上报但不要让页面崩溃 this.hasError true // 阻止错误传播到全局避免全局提示把用户吓到 return false } } /script这个组件的意义在于对于不重要的区块比如推荐位、广告位、图表卡片错误应该被局部吞掉并展示降级 UI而不是让整个页面白屏。全局体系负责兜底局部边界负责降级两者配合才是完整方案。6. 实际效果观察接入后团队的变化最后聊聊这个方案在实际项目中带来的改变这部分对接手老项目、想说服团队改造的人可能很有参考价值。接入全局错误处理体系大概两周之后我能明显观察到几个变化。第一新增页面代码变薄了不用再写一堆错误提示逻辑新来的同事看代码也更容易理解主干逻辑。第二线上错误的可见性大幅提高。过去用户报障我们要反复问你当时在做什么现在直接查监控后台错误日志里带着组件路径、路由、版本号大部分问题几分钟就能定位。第三错误分类之后基础设施团队能更精准地判断后端接口稳定性哪些接口错误率高在监控面板上一目了然。当然上线初期也出现过误报。我们曾经把 Chrome 扩展注入的脚本错误也当成了自己的错误上报导致某类错误量瞬间暴涨。后来在忽略列表里加上了chrome-extension://前缀并把非当前域名来源的错误降级为warning才恢复正常。这类细节需要在实际使用中根据自己项目的用户环境逐步完善。还有个小技巧分享给你上报字段里一定要带版本号和路由。版本号能帮你判断错误是否已在新版本修复路由能告诉你用户是在哪个页面触发的问题。没有这两个字段线上错误的排查效率至少低一半。我见过只上报错误堆栈、没有任何上下文信息的项目后端同事想帮忙排查都无从下手。全局错误处理体系不是一项可有可无的增强它是前端工程质量的基础设施。做一次配置所有页面、所有组件、所有异步任务都自动获得统一的错误兜底能力省下来的时间远大于搭建它花费的时间。如果你也在为重复处理异常头疼按这套思路去梳理你的项目我相信很快就能看到变化。
返回列表