前言
想简单聊一下我在开发过程中遇到 Bug 时,常用的一些调试思路。
我个人比较依赖“先建模,再验证”,很多问题其实不用一上来就狂加日志。
1)先搞清楚:这是业务失败,还是异常失败?
当 Bug 出现时,第一步不是急着改代码,而是先判断问题发生在哪一层:
- 是调用方逻辑写错了?
- 是网络请求封装层处理错误了?
- 是接口返回的业务失败(code != 0)?
- 还是异常失败(timeout / 500 / json 解析失败)?
因为不同失败类型,走的代码路径完全不同:
业务失败一般走失败分支;异常失败才会进入 catch。
2)案例1:为什么会出现两次 Toast?
我最近遇到一个问题:测试反馈说点击某按钮后,故意让接口返回错误,会出现两个 Toast。
- 第一个 Toast 符合预期:接口返回 message
- 第二个 Toast 不符合预期:提示“网络异常”
这个时候我会先在脑内对流程建模(大概如下):
- 点击按钮 → 参数校验
- 进入请求封装层 → 发起请求
- 收到响应 → 解析数据
- 回到业务函数 → 根据成功/失败进入分支
- 如果是异常失败(如超时),可能会进入 catch
因为第一个提示是接口 message,说明业务层一定执行到了“失败分支”。
而第二个“网络异常”通常来自网络层统一处理(比如拦截器 onError / catch)。
所以我会按最短路径排查:
- 失败分支里是否 Toast 过?
- catch 是否 Toast 过?
- 网络层封装是否有统一 Toast?
最后定位到重复提示的来源后,修复即可。
而最终排查我也得以确认,这个问题是之前的工程师在进入失败分支后直接强行让接口走进了catch才最终导致了这个问题
3)案例2:随机出现“售后金额=0”怎么查?
我之前做过一个售后申请功能,在极少数情况下会出现“售后价格为 0”的问题。
这个问题完全随机、难以复现,因此长期没解决。
我后来换了思路:与其等它复现,不如从结果倒推整个链路可能出问题的点:
- 提交前有类型转换 → 是否可能拿到了 null 或错误类型(尤其是 JS)?
- 价格计算过程较复杂 → 是否因为浮点精度问题导致结果异常?
- 页面进入时要请求订单数据 → 是否存在接口超时/卡住,用户提前操作导致数据未准备好?
- 为了防止再次发生 → 前后端关键节点都加数据校验与兜底策略
这套做法的核心是:
即使暂时找不到根因,也要先让系统不再产生错误结果。
后续多年这个问题没有再出现,直到后来排查订单关联 bug 时才最终确认:
后端订单接口在极端情况下会因为索引问题导致响应超时,从而触发了这条异常链路。
总结
调试能力不是“会记 API”,更多是“会建模 + 会倒推”。
如果你也有类似的调试套路,欢迎一起交流分享。