如何定位&排查BUG
定位排查顺序
1.进行复现
2.界面/前端初步分析
3. 接口层抓包分析
4. 日志追踪分析
5. 数据层验证 (DB + 缓存)
6. 提出假设 & 针对性验证
7. 报告与跟进
第一步:进行复现
目的:尽全力找到稳定复现的方法。这是定位的基石!如果无法稳定复现,定位将极其困难
固定变量: 使用相同的账号、相同的数据、相同的环境
记录复现条件: 成功复现时的所有细节
第二步:界面/前端初步分析
目的:通过抓包工具等快速判断是否是纯前端问题(如 JS 错误、样式问题)。如果是,直接报告前端开发。如果前端无报错且 Network 显示调用了后端接口,则进入下一步
第三步:接口层抓包分析
目的:确定请求是否成功到达服务端?服务端是否正确接收和处理了请求?响应是否符合预期?
使用工具: Fiddler, Charles, 浏览器 Network Tab (F12)。
操作:
1、清除现有抓包记录。
2、执行复现 Bug 的操作步骤。
3、停止抓包,分析相关请求。
分析点:
请求:
1、请求的url是否正确
2、请求参数(字段名、数据类型、值)是否与接口文档规定的一致
响应:
3、状态码:200 OK (成功), 4xx (客户端错误), 5xx (服务端错误)
4、响应体:结构是否符合接口文档定义、关键字段的值是否正确?返回的数据量、格式是否异常?
定位结果:
1、如果请求参数错误或缺失 -> 前端问题。
2、如果状态码是 4xx 且响应中有明确错误信息 (如 Invalid token, Missing parameter 'xxx') -> 根据信息定位(前端传参问题或后端校验逻辑问题)。
3、如果状态码是 5xx -> 严重后端错误,进入日志分析阶段。
4、如果状态码是 200 但返回数据错误 -> 核心线索! 记录下错误的返回数据,这直接指向后端逻辑或数据源问题。进入日志和数据库/缓存分析阶段
案例1:用户在某个页面进行提交时,页面报错,并且无法提交成功
排查步骤:进行抓包,发现请求参数 中有一个字段
"quantity"前端传的是字符串"2",但接口文档要求是整数2,定位:为前端参数类型处理错误
案例2:商品列表页显示的价格和点进商品详情页的价格不一致。
排查步骤:抓包对比两个接口
/api/products和/api/products/{id}的响应。发现列表接口返回的某个商品price字段是 99.9,而详情接口返回的是 109.9。定位:后端两个接口可能查询了不同的数据源或使用了不同的计算逻辑。(根据你的预期结果就能判断是哪个接口的数据不正确,有时间的话可以继续细究出现问题的接口取的数据源是哪个)
第四步:日志追踪分析
目的:通过日志还原请求在服务端的执行路径,找到逻辑出错点、数据错误点或异常抛出的位置。
如果开发人员自定义的业务日志比较规范,其实直接通过日志排查问题是最快的,这也是我平常用得最多的方法
操作:
获取权限/位置: 知道目标服务的日志存放在哪里(咨询对应开发)
输入命令进入对应服务的日志文件内;比如:
cd /data/service/salon-order/logs进入order服务的日志进入到对应的服务之后,输入查看具体某一天日志的相关命令 ,比如:
tail -f 1000 salon-order.2025-03-26.0.log 实时查看最后1000行记录(最常用的)
定位相关日志:
时间戳: 根据抓包中请求发生的时间戳定位日志。
关键标识:
1、TraceID / RequestID: 最有效! 分布式系统中贯穿整个请求链路的唯一ID。在抓包的请求头或响应头中(不过也要看公司开发的规范,有些开发可能不会加这个标识)
2、通常能找到。用这个ID在日志系统中搜索,能看到该请求在所有相关服务中的完整执行路径日志。
3、用户ID / 订单ID / 业务ID: 如果无 TraceID,用与 Bug 直接相关的业务ID搜索。
4、接口路径 / 方法名: 搜索处理该请求的 Controller 或 Service 类名/方法名。
常用命令:
tail -f salon-order.2025-03-26.0.log |grep"关键字" 实时查看包含关键字的日志
cat -n blessed-behavior.2024-04-26.0.log |grep "12343" 查看当日全部日志中某个关键字的日志
分析日志:
入口/出口: 确认请求到达了哪个服务、哪个接口。
关键逻辑分支: 查看代码中关键
if/else、switch的判断条件和走向日志。关键变量值: 日志中打印的重要方法参数、中间计算结果、数据库查询条件/结果。对比这些值是否符合预期?
外部调用: 调用其他服务、消息队列的结果是否成功?
关键线索 - ERROR 日志 & 异常堆栈:
1、找到
ERROR或WARN级别的日志。2、仔细阅读异常信息 (
Exception Message) 和堆栈跟踪 (Stack Trace)。 堆栈跟踪直接指向抛出异常的代码文件、类名、方法名和行号!这是定位根源的最强有力证据之一。
示例:

案例1:计算订单优惠金额不正确。
排查:查看服务层计算逻辑的 DEBUG 日志,发现日志打印了
originalPrice=100, discountRate=0.2 (20%),但下一行日志计算discountedPrice=80(100 * (1-0.2)) 正确。继续看,日志显示
finalPrice = discountedPrice - couponAmount,而couponAmount的值是30,导致finalPrice=50。但预期优惠券最多抵扣 20 元。定位:优惠券金额校验逻辑未生效,或者从数据库/缓存查询优惠券金额错误(此时需要结合数据库定位)。
案例2: (空指针异常 - NullPointerException): 用户点击某个功能按钮后页面报 500 错误
查看应用错误日志:
ERROR [http-nio-8080-exec-5] c.e.s.UserService - Failed to get user profilejava.lang.NullPointerException: Cannot invoke "com.example.model.User.getAddress()" because "user" is nullat com.example.service.UserService.getUserDetail(UserService.java:45)at com.example.controller.UserController.getProfile(UserController.java:32)... (更多调用栈)定位:日志清晰指出在
UserService.java文件的第 45 行,尝试调用一个User对象 (user) 的getAddress()方法,但user对象本身是null。需要检查第 45 行之前获取user对象的逻辑为什么返回了null(可能是数据库查询没结果,或者参数错误导致查询条件无效)
第五步:数据层验证 (DB + 缓存)
目的:确认数据在数据库和缓存中的状态,判断问题是出在数据本身(源头错误)、数据访问逻辑(SQL/缓存操作错误)还是数据一致性(DB和缓存不同步)。
数据库查询(DB)
工具/方法:Navicat或其他可视化工具、命令行
一般就是直接去对应的表里查数据,所以要对所测功能涉及的数据库很清晰,这样排查问题快些
检查点:
数据存在性: 相关的记录是否存在?
数据准确性: 关键字段的值是否正确?是否和接口返回的错误数据、日志中的值一致?
数据状态: 状态字段(
status)是否符合业务逻辑?数据关联性: 外键关联的数据是否存在?(如订单的用户ID是否有效)
事务: 相关的更新操作是否成功提交?
缓存检查
工具/方法: redis-cli, Redis Desktop Manager, 缓存控制台;这里需要了解一些常用的redis命令;
检查点:
1、Key 是否存在?
2、Value 值是什么? 是否与数据库源数据一致?是否过期(TTL)?
案例1:用户修改了收货地址,但下单时还是显示旧地址。
排查:查询
user_address表,发现该用户最新的is_default地址标志确实是旧的地址ID。定位:后端更新默认地址的逻辑可能未正确更新
is_default标志
案例1延伸出的案例2:
如果数据库中
is_default标志已经正确更新成为新地址了,但是页面还是显示旧地址那这里后端有可能是取缓存的内容,在更新默认地址时,只更新了数据库,没有更新缓存。所以这里还要和后端确认取值逻辑;
第六步:提出假设 & 验证
综合信息: 将前面步骤收集的所有信息(现象、请求、响应、日志、DB数据、缓存数据)整合起来。
提出假设: 基于证据,推测可能导致 Bug 的根本原因。
修改输入: 尝试不同的输入数据,看是否能规避或触发 Bug,验证边界条件。
第七步:提交bug与跟进
- 提交bug,主要包含以下要素:
Bug 标题: 简明扼要描述问题本质。
环境: 复现环境。
复现步骤: 清晰、最小化的步骤。
预期结果 & 实际结果: 对比。
定位过程与关键证据 (核心):
a.抓包截图(请求/响应 - 突出错误参数或响应数据)。
b.关键日志片段 (特别是 ERROR 日志和堆栈 - 脱敏后)。
c.数据库查询结果截图(突出错误数据)。
d.缓存查询结果截图(如果相关)。
e.你的分析与结论 (定位到的根本原因)。
沟通协作: 与开发人员讨论你的发现和分析,确认定位结果。
跟进修复: 验证开发提供的修复是否真正解决了问题。进行回归测试。
