做前后端分离的时间长了你会发现一个扎心的事实大部分性能问题、逻辑Bug、环境故障最后都卡在“这个Bug到底该谁去查”上。前端说是后端接口返回格式不对后端说是前端根本没把参数传过来两边一扯皮半天就没了。我见过太多团队代码写得挺利索一到联调阶段就开始互相甩锅最后只能靠项目经理拍桌子定责任。这种局面其实完全可以避免前提是你有一套清晰的定位分析思路。这篇文章就是day06的完整记录主题就是“如何定位分析前后端Bug”。我不会讲那种“打开控制台看报错”的废话而是把我实际排查过的问题、踩过的坑、以及我现在处理前后端Bug时的一套固定动作全部拆开来讲。无论你是刚开始接触前后端分离项目的新手还是已经被联调折磨过一阵子的初级开发这篇文章都能帮你少走不少弯路。1. 先搞清楚这个Bug到底是谁的“锅”1.1 三条快速判断路径前后端分离项目里前端和后端之间就隔着一层HTTP协议。一个请求发出去要么到不了后端要么后端处理出错要么响应回来了但前端不会用。所以定位Bug的第一步从来不是看代码而是先回答一个问题这条请求链路断在了哪一段。我自己的判断路径有三条基本能覆盖绝大多数场景。第一条打开浏览器开发者工具刷新页面看Network面板里有没有对应的请求。如果连请求都没有那问题大概率出在前端要么是按钮没绑事件要么是接口地址写错要么是某个JavaScript异常导致后续代码根本没执行。这种情况后端完全不知情你让后端去查他的日志他当然查不出东西来。第二条请求发出来了但状态码是4xx或者5xx。这时候问题就在后端。但要注意4xx比如400、404、405通常说明客户端请求有问题5xx比如500、502、503才说明服务器端处理出错。很多人一看到500就往后端甩其实有些500是Nginx配置错误导致的跟应用代码一点关系都没有。第三条请求返回200了但页面表现不对。这就有意思了说明后端把数据都给出来了前端解析、渲染或者状态管理环节出了问题。这种Bug最隐蔽因为两边都没报错但用户就是看不到想要的结果。这三条路径听着简单但实际操作中需要反复练习。我现在接到一个Bug报告脑子里会立刻把这三条路径过一遍基本上十分钟内就能判断出问题归属。1.2 前端、后端、联调环境的特征差异光判断出是“前端的锅”或者“后端的锅”还不够你还得理解不同类型问题各自的特征不然很容易被表象带偏。前端问题的典型特征是大部分发生在浏览器环境跟浏览器类型、版本、屏幕尺寸、用户操作路径都有关系。比如同一个页面Chrome里正常换成某个旧版浏览器就白屏再比如用户快速点击提交按钮两次结果请求发出了两条这种交互时序问题前端最典型。前端Bug还有一个特点错误信息经常出现在Console面板里但你可能有一堆插件和第三方脚本也在打印信息真正的报错容易被淹没。后端问题的典型特征是与用户操作路径无关只要输入相同的参数一定会得出相同的结果。所以后端Bug最可靠的处理方式就是——拿到请求参数本地复现。如果同样的参数本地跑不起来那就是环境问题如果本地能复现那就是代码逻辑问题。后端Bug的表现形式也很直接异常堆栈、错误日志、状态码。联调环境的问题则更隐蔽。最典型的就是跨域。前端在localhost:8080后端在localhost:9090两边单独跑都正常一联调就报“CORS”这类问题既不是前端代码问题也不是后端业务逻辑问题而是HTTP通信策略问题。还有一种是代理配置问题前端开发服务器配了代理但生产环境Nginx转发规则没配好就会出现开发环境正常、生产环境接口全部404的诡异情况。我把这三种类型的特征整理成了自己的排查优先级先看请求层确定请求通没通再看数据层确定响应对不对最后才看渲染层确定页面为什么不对。2. 前端侧的定位利器开发者工具与调试基本功2.1 Console面板不是所有红字都是真凶很多人一看到Console面板有大片红色就慌了觉得JS代码炸了。其实Console里的错误分很多种有些是致命的有些只是警告还有一些是第三方脚本“误报”的。我用Console面板有一个习惯先看错误详情再看出现位置最后才看报错内容。比如常见的“TypeError: Cannot read properties of undefined (reading map)”这个报错的关键信息不是“reading ‘map’”而是undefined——哪个变量是undefined。展开报错堆栈它会告诉你是在哪个文件、哪一行触发这时候你再去代码里看那个变量从哪来。大部分情况下这个变量来自接口响应接口没返回你预期格式的数据前端一取属性就炸了。Console面板我还会配合一个技巧临时加日志。直接在代码里写console.log然后刷新页面看输出顺序能帮你确认代码执行流程是否正确。这个方法很笨但在复杂数据流转中特别有效。还有一种情况要注意Console里冒红色的有时候是浏览器扩展干的。我排查过好几个“诡异Bug”最后发现是浏览器里装的翻译插件把DOM结构改了。所以我建议你在排查前端问题时先开一个无痕窗口禁用所有扩展再复现问题。2.2 Network面板接口请求的“监控录像”如果说Console是报错入口那Network就是整个请求链路的“监控录像”。每一个请求的请求头、请求参数、响应体、耗时、状态码全部记录得清清楚楚。我定位前后端Bug时80%的时间都花在Network面板上。具体怎么做刷新页面找到出问题的接口点开看四个关键信息请求URL看路径对不对。前端配的接口地址和后端实际的接口定义是否一致很多人拼错路径都没发现。请求方法看是GET还是POST。后端接口定了POST前端用GET去调直接405。请求载荷这是定位后端参数问题的核心。看前端到底把哪些字段发出去了字段名和后端实体类是否能对上。实际工作中最常见的问题是前端传的字段名是userName后端接口接收的是name结果后端一直拿不到值。这种问题你不看Network面板光看后端日志根本发现不了。响应内容看后端到底返回了什么。如果请求状态码是200但响应体里是“{code:500,msg:系统异常}”说明HTTP层面是成功的但业务层面出错了。这时候问题依然在后端只是它的错误信息可能写在了业务错误码里而不是HTTP状态码里。Network面板里还有个特别容易被忽略的功能查看请求耗时。点开某个请求的Timing标签你能看到DNS解析、TCP连接、TLS握手、等待服务器响应、内容下载各花了多少时间。如果“Waiting for server response”的时间特别长说明后端接口处理太慢这才是性能问题的根源。2.3 用状态码快速判断问题归属状态码是前后端约定好的“暗号”掌握了状态码含义你能少吵很多架。我给自己整理了一个速查表贴在工位上排查问题时直接对照状态码含义问题归属排查方向200请求成功正常/前端检查渲染逻辑301/302重定向前后端都有可能检查路由、鉴权配置400请求参数错误前端检查参数格式、字段名401未认证前端/联调检查Token是否存在、是否过期403无权限前端/联调检查用户权限、角色配置404接口不存在前后端都有可能检查URL路径、Nginx转发规则405方法不被允许前端检查请求方法415不支持媒体类型前端检查Content-Type500服务器内部错误后端/环境检查后端日志、异常堆栈502网关错误环境/运维检查上游服务是否存活503服务不可用环境/运维检查服务负载、限流配置504网关超时环境/后端检查后端慢接口、超时配置你注意看这些状态码里没有一个是单纯由一方决定的很多都要两边结合排查。比如404前端明明请求了/api/user后端却报404这时候你要先确认这个接口在后端是不是真的存在再确认Nginx有没有把请求正确转发到后端服务。3. 后端侧的定位心法日志、断点与参数校验3.1 日志是最好的破案线索前端排查靠浏览器后端排查靠什么第一靠日志第二靠断点第三靠参数校验。很多后端新手遇到Bug第一反应是“加断点调试”。这没错但在分布式环境、微服务架构下你根本没法在本地把所有服务都跑起来这时候日志就成了唯一可靠的线索。我自己处理生产环境问题第一条命令永远是“查日志”。但日志也不是随便打的。我见过太多团队日志打了跟没打一样全是“ERROR系统异常”至于哪个接口、哪个参数、哪个服务的哪一行代码报错一概不知。这种日志还不如不打。真正有用的日志必须包含三个要素接口标识、请求参数、异常堆栈。接口标识让你知道是哪个功能出的问题请求参数让你能拿同样的参数在本地复现异常堆栈让你知道错在哪一行代码。我写后端接口时习惯在入口就打印一条“请求日志”包含请求路径、请求方法、关键参数在处理完业务后打印一条“响应日志”包含响应码、耗时在捕获异常时打印一条“异常日志”包含完整堆栈。三层日志一打排查问题时基本不需要瞎猜。还有个细节日志要分级。Debug、Info、Warn、Error这四级不要滥用。我在排查问题时只看Warn和Error级别Info级别用于确认流程是否正常执行。如果你把所有的调试信息都打在Info级别关键错误反而会被淹没。3.2 参数校验很多Bug死在这里后端排查问题时有一个环节我建议所有人优先做校验入参。我自己统计过后端接口的Bug里有三成左右是参数问题导致的。什么叫参数问题比如前端传了一个空字符串后端没有做校验就直接塞进数据库结果数据库报错前端传了一个不符合格式的日期字符串后端用SimpleDateFormat解析直接抛异常前端传的数字过大后端用Integer接收直接溢出。这些问题有个共同点它们不是业务逻辑错了而是数据进来之前没有把好关。所以我现在写后端接口不管时间多紧都会在Controller层做参数校验。如果校验不通过直接返回业务错误码而不是把异常一路抛到数据库层。排查参数问题时最有效的办法是“原样打印入参”。你在接口入口处加一个日志把前端传过来的原始参数完整打印出来然后用这个参数在本地发起一个同样的请求看能不能复现。这种方式能把很多“偶发Bug”变成“必现Bug”。3.3 用Postman/Apifox做最小化复现我处理后端Bug时有个习惯绝不直接在前端页面上点来点去地复现而是先用接口调试工具做“最小化复现”。所谓最小化复现就是只保留最必要的请求参数把前端那些无关干扰全部排除掉。比如用户反馈某个列表接口偶尔报错我在后端日志里找到了当时的请求参数然后把参数原封不动地复制到Postman里发起请求一分钟内就能确认这个Bug是否与前端有关。如果再配合上断点调试看参数进入方法后一步步走到了哪那基本就没有定位不了的Bug。用接口调试工具时要注意两个与浏览器不同的地方Cookie和请求头。浏览器会自动带上当前站点的Cookie但Postman默认不带。有些接口依赖登录态你在Postman里测试时要手动把Token加到请求头里否则会一直报401。另一个是User-Agent有些网关或者后端服务会根据User-Agent做限制你从Postman发请求和从浏览器发请求可能会得到不同的结果。我比较推荐的组合是后端开发用Postman因为轻量、支持环境变量前端联调用Apifox因为可以直接从后端接口定义生成Mock数据两边对接口比较方便。工具不在多顺手就行关键是掌握“用纯请求复现问题”这个思路。4. 前后端联调阶段的“灰犀牛”跨域、环境与依赖问题4.1 跨域问题怎么验证和解决联调阶段最容易碰到的第一个“拦路虎”就是跨域。浏览器为了安全默认阻止页面从一个域名去请求另一个域名的接口。你前端在http://localhost:5173后端接口在http://localhost:8080浏览器会拦截掉这个跨域请求。遇到跨域报错很多人第一反应是让后端加CrossOrigin注解。这个做法没错但只是开发阶段的临时方案。生产环境里如果前端静态资源在Nginx上后端服务也在Nginx后面最常见也最推荐的做法是用Nginx做反向代理通过配置location /api/ 把请求转发到后端服务这样浏览器看到的始终是同一个域名不存在跨域问题。我自己验证跨域是否解决的方法很简单直接打开Network面板看那个报错的请求响应头里有没有Access-Control-Allow-Origin。如果有并且值和当前页面域名匹配就说明后端CORS配置没问题如果没有那就是后端没处理跨域。还有一类奇葩的跨域问题前端配了代理请求URL写的是/api/users浏览器看到的也是/api/users但实际上Nginx或者Webpack Dev Server把请求转发到了后端服务的某个路径上结果路径映射错了接口404。这种问题你在浏览器端怎么都排查不出来必须去查代理配置。4.2 环境类问题的典型特征代码没动环境换了就炸我特别想强调一类问题环境类问题的典型特征就是“代码没动环境换了就炸”。开发环境好好的部署到测试服务器就报错昨天还好好的今天一到公司刷新就白屏。这类问题最容易被当成前后端代码Bug来排查排查了大半天最后发现是环境配置变了。这类问题我遇到的次数不少总结下来有几类数据库连接不上最典型的是数据库地址配置到了旧服务器或者用户名密码改了没同步依赖包版本不一致本地是Node 18服务器是Node 16一个语法支持不对就报错环境变量缺失代码里读了一个配置项部署的时候没在环境变量里设置文件权限问题上传的图片目录没有写权限。遇到这类问题我一贯的建议是先不碰代码先把“环境差异”找出来。对比本地环境变量、对比依赖版本、对比操作系统版本。很多时候问题就出在这些“你在本地根本不会注意到的细节”上。4.3 依赖安装类问题案例cannot find native binding这里我想讲一个特别典型的案例。之前我有个同事部署一个Node.js项目执行npm install的时候一切正常但跑npm run serve的时候直接报错cannot find native binding. npm has a bug related to optional dependencies。这个报错出来的瞬间他整个人都懵了以为是代码问题在项目里翻了半天也没找到头绪。后来我帮他排查了一下发现根本不是代码问题而是依赖安装阶段出了问题。Node.js很多包有原生编译模块比如node-sass、sharp、bcrypt这种它们需要根据当前Node版本编译出对应的二进制文件。一旦Node版本变了或者安装时没有下载到对应平台的预编译二进制就会出现cannot find native binding。当时的解决办法很简单删掉node_modules目录和package-lock.json重新执行npm install。有时候还需要清理npm缓存npm cache clean --force。如果还不行就要检查Node版本是否与项目要求的一致用nvm切换Node版本后重新安装依赖。这类问题的排查思路是报错信息里带着native、binding、node_modules这些关键词而且你最近刚换过Node版本、刚把代码克隆到新机器、刚刚重新执行过依赖安装。遇到这种组合就别去翻业务代码了直接重装依赖。5. 实战复盘三个真实场景的定位全过程5.1 场景一登录接口500后端却“没报错”之前做过一个SpringBoot Vue的登录功能测试反馈说账号密码输入正确但点击登录后提示“服务器错误”。我第一反应是看Network面板找到登录接口状态码是500这个不用猜肯定是后端出错了。我登录后端服务器先看应用日志结果日志库里没有这个请求的任何输出。这就奇怪了请求都到了服务器怎么可能没日志我特意去确认了一下才发现因为这个环境是测试环境后端服务日志级别被调成了WARN接口入口的Info级别请求日志根本没有打印出来。也就是说不是没有报错而是报错信息被日志级别给“吞”了。把日志级别调到Debug后重新发起登录请求很快看到一条异常数据库连接超时。进一步排查发现测试环境的数据库地址配置文件被改成了另一个内网IP那台数据库服务器当天刚好在重启。这个Bug跟登录逻辑没有任何关系纯粹是环境配置变了。这个案例给我的教训很深后端排查问题时第一步先确认日志真的打出来了而不是盲目地去翻业务代码。5.2 场景二接口返回正常前端页面却空白有一次做数据大屏后端接口返回的是一串JSON数组Network面板里看响应体数据完全正常状态码也是200但页面上就是什么都不显示。我打开Console没看到报错。这就更诡异了。后来我用断点调试的方式一个个地方检查最后发现问题出在前端的数据解析上后端返回的字段是itemName但前端代码里取的是name后端返回的图片地址是一张相对路径但前端写成了绝对地址。数据明明拿到了只是前端不知道去哪找。这种问题最坑人就是因为它不报错。JavaScript是弱类型语言取一个不存在的属性只会返回undefined不会像Java那样直接抛NullPointerException。所以前端在取接口返回数据的字段之前一定要先打印一下原始数据长什么样确认字段名完全一致再继续写业务逻辑。5.3 场景三npm install 报错差点“误伤”后端还有一次前后端联调的时候前端机器一直启动不了项目报错信息是npm install那一步失败。前端同事一脸委屈地说“我页面都起不来肯定不是我的问题后端先查一下接口”。我看了一眼报错里面有optional dependencies、node-sass这种词就告诉他这跟前端代码和后端代码都没关系纯粹是依赖安装失败了。让他先检查Node版本然后删掉node_modules重新安装。他照做后问题立刻解决了。这类问题偶尔会出现在团队协作中大家容易被“报错”两个字吓到以为是什么深不可测的问题。我现在的习惯是看到npm、webpack、gradle、maven这些构建工具相关的报错先别急着归罪于代码先看构建日志的结尾部分它往往会给出最根本的失败原因。6. 避坑清单与经验沉淀让Bug定位变成肌肉记忆6.1 排查工具速查表把工具用熟比记一堆命令更有用。下面是我日常排查前后端Bug时最常用到的工具清单每类工具都有明确的使用场景分享出来供你参考使用场景工具核心用途前端请求分析浏览器Network面板查看请求URL、请求参数、响应内容前端运行时报错浏览器Console面板查看JS异常、Warn警告前端状态管理Vue Devtools / React DevTools查看组件状态、Pinia/Redux数据接口单测/复现Postman / Apifox独立发起请求排除前端干扰后端日志排查grep / tail / Kibana搜索日志关键字、查异常堆栈后端实时调试IDEA/VS Code断点调试逐行观察参数变化抓包工具Charles / Fiddler / Wireshark查看完整HTTP流量、转发规则数据库排查Navicat / DataGrip验证SQL语句、检查数据是否符合预期这些工具不在于装得多而在于你每个都能用明白。比如Network面板里怎么看特定接口的请求头Console面板里怎么用filter只显示错误信息Postman里怎么设置环境变量切换测试和正式环境。这些基本功练好了排查Bug的速度至少提升一倍。6.2 常见的定位误区排查Bug最怕的不是技术不够而是方向搞错。我总结了几个自己踩过坑的典型误区。一个误区和“翻代码”有关。很多新人接手Bug第一件事就是把相关代码翻一遍从Controller翻到Service再翻到Mapper眼睛看花了也没发现问题。正确的做法是先看“事实”请求日志有没有打印请求参数是什么异常堆栈指向哪一行。事实清楚了再去看代码效率高得多。另一个误区是“凭经验猜”。有个需求是列表查询上报的Bug是“数据不对”你第一反应是SQL写错了。但实际上可能是缓存没刷新也可能是前端用了旧数据渲染。我现在的原则是不拿到第一手证据不轻易下结论。先通过Network面板看响应确认数据对不对再通过后端日志确认这个响应是谁生成的最后才去看业务代码。还有一个误区是“忽略版本号”。SpringBoot 2.x和3.x的很多写法差异、Vue 2和Vue 3的API差异、Node14和Node18的行为差异都可能让同一套代码在不同环境表现完全不同。排查问题时先确认运行环境版本和项目要求的版本一致很多困扰你半天的问题一下子就解开了。6.3 我建议每个团队都建立的“Bug上报三板斧”代码会越写越多Bug也会越遇到越多。我现在在团队里推行了一个办法效果不错分享给你任何人在群里反馈Bug必须附带三条信息——操作步骤怎么触发的最好有录屏或者截图、现象描述页面报什么错、弹什么提示、环境信息浏览器类型与版本、接口地址、登录账号。这三条信息不是乱要的。操作步骤用来复现问题现象描述用来判断是前端渲染问题还是后端数据问题环境信息用来排查是不是跟浏览器兼容、登录态、网络环境有关。有了这三条信息我收到Bug报告后就直接开始定位省去了大量来回追问的时间。如果你们团队还没有这样的协作规范我强烈建议试试它就是能把几天的排查时间压缩到几个小时。说到底前后端Bug定位分析并不是什么高深的技术它更像是一门“排查的手艺”。你需要对请求链路足够敏感对工具足够熟练对问题保持足够的冷静。我在实际工作中最大的体会是遇到Bug先别慌别急着甩锅先把链路走一遍看清请求长什么样、响应长什么样问题基本就水落石出了。这些方法如果你能真正用起来联调扯皮的烦恼会少一大半。
阅读完成 · 觉得有帮助?