错误处理的混乱
项目里的错误处理很乱,每个地方处理方式都不一样:
- 有的用 try-catch,有的用 Promise.catch
- 有的打印日志,有的不打印
- 有的显示错误提示,有的不显示
- 有的上报错误,有的不上报
用户报错,我们根本不知道哪里出问题了。看日志,日志也不全。看监控,监控也不准。
问题一:错误被吞掉
最严重的问题是错误被吞掉。有些地方用了 try-catch,但 catch 里什么都没做:
try { doSomething(); } catch (e) { // 什么都没做 }错误发生了,但没有任何提示。用户不知道出错了,我们也不知道。
问题二:错误信息不统一
错误信息也不统一。有的错误信息是中文,有的是英文。有的错误信息很详细,有的很简单。
用户看到错误,不知道是什么意思。我们排查错误,也不知道从哪里开始。
问题三:错误上报不完整
有些地方上报了错误,但信息不完整。只有错误消息,没有堆栈、没有上下文、没有用户信息。
收到错误报告,但不知道在哪里发生的,也不知道怎么复现。
统一错误处理
花了 3 个月,我们统一了错误处理:
1. 错误分类
把错误分成几类:
- 网络错误:API 请求失败
- 业务错误:业务逻辑错误
- 系统错误:系统异常
- 用户错误:用户输入错误
不同类型的错误,处理方式不同。
2. 错误处理中间件
做了错误处理中间件,统一处理错误:
- 捕获所有错误,不遗漏
- 统一错误格式,方便处理
- 自动上报错误,包含完整信息
- 显示错误提示,用户友好
3. 错误上报
统一错误上报,包含完整信息:
- 错误消息和堆栈
- 用户信息和环境信息
- 操作路径和上下文
- 时间戳和唯一 ID
这样收到错误报告,能快速定位问题。
4. 错误提示
统一错误提示,用户友好:
- 网络错误:显示"网络连接失败,请检查网络"
- 业务错误:显示具体的业务错误信息
- 系统错误:显示"系统异常,请稍后重试"
- 用户错误:显示具体的输入错误
遇到的坑
坑一:异步错误
异步错误的处理很麻烦。Promise 的错误要用 .catch(),async/await 的错误要用 try-catch。
我们统一用 async/await + try-catch,但有些地方还是用 Promise,要逐步迁移。
坑二:React 错误边界
React 的错误要用 Error Boundary 捕获,不能用 try-catch。我们做了全局 Error Boundary,但有些错误还是捕获不到。
后来用了 react-error-boundary,才解决了问题。
坑三:错误上报的性能
错误上报如果同步,会影响性能。我们改成异步上报,用队列批量上报,才解决了问题。
现在的状态
统一错误处理后,效果很明显:
- 错误不再被吞掉,都能捕获到
- 错误信息统一,方便排查
- 错误上报完整,能快速定位
- 错误提示友好,用户体验好
如果重新开始
如果重新做一个项目,我会:
- 一开始就统一错误处理,不要后面改
- 做好错误分类,不同类型不同处理
- 统一错误上报,包含完整信息
- 做好错误监控,及时发现问题
总结
错误处理很重要,但要统一。如果每个地方处理方式不一样,排查错误就很麻烦。
如果你们项目也有错误处理问题,建议统一错误处理,做好错误分类、错误上报、错误提示。虽然麻烦,但总比出问题好。
另外,错误处理要早规划,不要等出问题再处理。等出问题了,处理起来就很麻烦了。