做H5/WAP开发的人应该都有过这种体验:桌面上把页面调得妥妥当当,一扔到手机里就“原形毕露”,报错信息看不到、接口状态不知道、元素位置对不上。PC端一个F12能解决的事,到移动端要同时面对浏览器兼容、真机差异、WebView内核差异,连个console日志都只能靠alert去猜。vConsole、Eruda、Spy-Debugger这三款工具,分别覆盖了移动端调试最刚需的三件事:页面内看日志、页面内看网络、用PC远程操作真机。这篇把我实际用这三款工具的经验、选型思路和踩坑记录整理出来,适合刚接触移动端调试的前端开发,也适合做混合App或H5活动页的团队参考。
1. H5/WAP端调试为什么这么折腾
移动端调试难,难在环境不透明。你写的代码跑在手机浏览器里,或者在某App的WebView里,这层壳把很多信息挡住了。PC端开发者工具能看到完整的DOM、样式、控制台、网络瀑布,移动端默认什么都没有。报错可能被发布版吞掉,错误对象可能被打包工具压缩成一行乱码。就算打开手机浏览器的“开发者模式”,又能做的也相当有限,而且不同系统、不同内核的调试入口还不一样,想统一一套流程并不容易。
1.1 移动端和PC端调试环境的差距
PC端调试是所见即所得。按F12打开开发者工具,Elements面板直接改样式,Console面板看任何日志,Network能查请求头、响应体、耗时,鼠标悬停就能看盒模型。移动端如果要复现同样的事情,至少面临三个落差。
第一个落差是没有稳定的调试入口。不同浏览器、不同WebView暴露的能力不一致,同一个H5页面在A浏览器里能打开调试,在B浏览器里可能完全找不到入口。第二个落差是网络请求只能靠WeakNetwork工具或者服务端日志间接观察,拿不到完整的请求参数和响应体,前后端一扯皮就得翻日志。第三个落差是真机上的手势、软键盘、屏幕尺寸、安全区域这些因素,PC模拟器永远模拟不完整。比如某个输入框在iPhone上获取焦点调起软键盘后,整个页面被顶上去,底部按钮被安全区遮住,这种问题在PC上无论如何都复现不了。
这三个落差直接导致移动端调试的典型路径:先alert弹值,再console.log,然后在手机屏幕上截图发给后端。遇到接口参数对不上、页面渲染异常,还得开远程调试通道,有时候一根调试线不行、驱动不对,半天就没了。所以移动端调试工具要解决的,本质上是把PC端开发的“确定性”带回移动端,让你在手机上也能快速看到可读的报错、请求和页面结构。
1.2 从“alert弹窗”到“页面内调试台”的进化
早先的一些H5项目里,移动端调试几乎就是alert大法。alert能显示字符串,于是所有怀疑的变量都塞进一个alert里,然后一句一句地删。这种方式不是不能用,而是效率和表达能力太差。对象打出来是[object Object],数字和字符串混在一起容易看错,网络请求完全看不到,也没法动态执行代码。那时候遇到“页面白屏”,只能在代码里到处加alert,一遍遍刷新,运气好找到了,运气不好改一次刷一次,一下午就没了。
后来出现了一批注入页面的调试工具,思路是在页面里插入一段脚本,由这段脚本动态渲染出一个控制台面板。vConsole和Eruda就属于这一类。它们的优势非常明显:不依赖外部调试通道,只要页面能加载脚本,就能看日志,兼容Android和iOS的主流浏览器与WebView;同时可以通过发布开关控制是否加载,测试环境打开、正式环境关掉。Spy-Debugger则走了另一条路,它把手机和PC连接起来,让开发者用PC的键盘鼠标操作手机页面,相当于给真机开了一个远程开发的通道。
这两类工具并不冲突。我这里的实际用法是:日常联调用Eruda看页面日志和DOM状态,定位请求瓶颈用Spy-Debugger抓完整请求链路。先搞清楚它们各自能做什么、不能做什么,后面接入才不会手忙脚乱。
2. 选型之前先搞懂三款工具的工作原理
三款工具都是解决移动端调试的方案,但实现思路和适用场景差别很大。如果只是知道怎么引入,不理解它们的数据流和边界,遇到问题就容易乱。下面分开拆解。
2.1 vConsole:一个注入页面的轻量级控制台
vConsole的思路很直接:在页面加载一段JS,这段JS会在页面角落生成一个悬浮按钮,点击后展开一个类似PC控制台的面板。面板分成几个页签,包括Log、System、Network、Element等,可以看console日志、打印对象、查看网络请求的URL、状态码和耗时,还能看cookie和localStorage。实现上,它本质是把全局console方法包装了一层,同时通过钩子捕获XMLHttpRequest和fetch的请求,把请求信息透传到面板上。
使用vConsole的好处是轻,整包非常小,接入成本极低。不过它默认只显示自身存活期间产生的日志,如果你希望看到页面初始化早期的日志,必须确保脚本在业务代码之前执行,最好放在head里。另外,vConsole的Element面板并不是完整DOM树浏览,更多是查看元素基本信息,不像PC开发者工具那样可以精确选中元素改样式。所以它更适合快速定位JS报错、确认接口返回,不太适合做精细的样式调整。
我最早在一个移动端活动页里用vConsole,主要就是看接口返回。活动页的倒计时逻辑和领券结果都要依赖后端响应,当时后端说“接口没问题,是前端渲染错了”,我用vConsole的Network页签把请求参数和响应一截,发现确实有一个字段在服务端返回了空字符串。问题定位又快又清楚,比alert强太多。
2.2 Eruda:把开发者工具搬进手机屏幕
Eruda在定位上更像一个“移动端开发者工具套件”。它的默认面板包括Console、Elements、Network、Resources、Sources、Sensors等,功能覆盖比vConsole更全面。Elements面板可以像PC一样查看DOM树、修改属性;Sources可以查看页面加载的脚本并打断点,部分场景下可用;Sensors可以模拟地理位置、重力感应等。它还提供插件机制,按需扩展功能,比如加载Vue插件时可以直接检查组件实例状态。
Eruda的使用方式也基本是注入一段脚本,但默认面板是固定在页面底部的一块区域,可以通过配置调整主题、大小和是否自动打开。相比vConsole,Eruda体积更大、能力更强,也更接近桌面浏览器的开发体验。代价是如果业务代码先加载了,同样会漏掉部分早期日志;而且它的大型面板在某些低端机或小屏设备上会占用不少可视区域,需要注意及时折叠。
选型的时候,如果只是想看日志和请求,vConsole已经足够;如果需要频繁查看DOM、在线改样式、处理跨端页面,Eruda更合适。我后来在混合App项目里就把Eruda打进了测试包,测试人员报问题时能直接截图面板上的报错信息,比复制一串乱码有用得多。
2.3 Spy-Debugger:用PC接管手机页面的远程调试
Spy-Debugger跟上面两个不一样,它跑在PC上,通过npm安装后启动一个本地服务,这个服务会开启一个代理端口。手机和PC连在同一个局域网,手机网络代理指向PC的IP和端口,之后手机上的所有HTTP和HTTPS请求都会经过Spy-Debugger转发。开发者可以在PC的浏览器里打开一个控制页面,看到请求列表、请求详情、响应内容,甚至能用“远程inspect”能力操作手机上的页面:在PC端输入命令,在手机页面里执行JavaScript、查看元素、截屏。它本质上承担了“代理转发+远程控制”两层职责。
这种方案最大的价值是,它不需要在目标页面里注入任何脚本,所以对线上页面、第三方页面、甚至App内页面都能做接入。哪怕页面是打包后的压缩代码,也可以抓包。需要注意的是,调试过程中手机流量全部走代理,如果代理断开,页面会立刻无法加载。这个坑很多人踩过,我也是后来才习惯先检查代理状态。
另外,它只能看到由代理客户端发出的请求。如果某个App内嵌页面使用了不走系统代理的网络库,单独设置系统代理是抓不到的,后面我会专门说这种场景的替代方案。
2.4 三款工具对比与选型建议
| 工具 | 部署位置 | 主要能力 | 体积/性能 | 适用场景 |
|---|---|---|---|---|
| vConsole | 页面内注入 | 日志、网络请求、系统信息 | 轻量 | 自家H5快速看日志、确认接口 |
| Eruda | 页面内注入 | DOM、网络、资源、传感器等 | 较重 | 需要类桌面调试的复杂页面 |
| Spy-Debugger | PC端代理 | 抓包、远程操作、HTTPS解密 | 无需注入 | 线上/第三方页面、全流程排查 |
选型建议上,自研H5优先考虑vConsole或Eruda,vConsole看重简洁,Eruda看重功能;调试过程中需要看后端返回和请求头,优先Spy-Debugger;混合App内页面调试,推荐把Eruda内嵌进测试包,同时配合Spy-Debugger排查真机网络差异。三款工具不是互斥的,我通常在测试环境同时开着Eruda和Spy-Debugger,Eruda负责前端表现,Spy-Debugger负责完整请求链路,两边对照着看,很多“魔幻bug”都能快速收敛。
3. 从接入到日常调试的完整实操
这一部分直接给步骤,按我实际用的流程写。下面分别说三款工具怎么接、怎么配、日常怎么用。
3.1 vConsole接入与上线开关控制
接入vConsole最简单的方式是直接引入脚本并初始化。可以放在页面head里,保证在业务代码之前执行。示例:
<!DOCTYPE html> <html> <head> <script src="https://example.com/vconsole.min.js"></script> <script> var isDev = location.hostname.indexOf('test') > -1; if (isDev) { window.vConsole = new VConsole(); } </script> </head>注意,脚本加载地址只是一个示例,实际部署时应该把vConsole打包进项目,或者放到自己的CDN,避免调试器本身成为性能瓶颈。上线开关非常重要。我见过不止一次,调试工具被直接打包上线,结果用户手机上出现了一个悬浮按钮,既难看又有安全隐患。正确做法是构建时通过环境变量注入开关,测试包默认打开,生产包不引入脚本。如果只能用域名判断,记得区分二级域名和正式域名,不要用简单的includes匹配,比如“test.example.com”可能误伤正式域名。
初始化的时机同样有讲究。vConsole必须在业务代码前初始化,才能捕获业务脚本里的早期console和网络请求。如果业务代码已经执行完再new VConsole,之前的日志就彻底看不到了。有些团队为了省事,把初始化函数放在全局异常处理里做兜底,这只能捕获运行期错误,初始化之前的日志还是丢。
日常使用里,我最常用的是Network页签。接口请求顺序、返回状态、耗时都列在里面,接口出错时能一眼看出是不是后端问题。Log页签可以按级别过滤error、warn、info,定位报错很方便。它还支持在面板底部输入表达式直接执行,相当于一个实时控制台,改页面状态、调函数都很方便。
3.2 Eruda接入与插件按需加载
Eruda的接入类似,直接在页面加载时初始化。默认配置下它会在页面底部展开一个工具条,点击后弹出完整面板。基础用法:
<script src="https://example.com/eruda.min.js"></script> <script> if (isDev) { window.eruda.init({ container: document.body, tool: ['console', 'elements', 'network', 'resources'], useNativeConsole: true }); } </script>这里的tool数组是控制台、DOM、网络、资源几个基础面板,不需要的可以去掉,避免面板过重。如果项目用了某个前端框架,还可以按需引入对应的插件包,比如Vue插件,这样在面板里能直接看到组件实例和状态。插件通常也是在init之前加载,然后通过配置注册进去。不要一次性把所有插件都装上,低端机实在扛不住,先上最常用的。
实际使用中,Eruda面板打开后,可以在Elements面板点击任意DOM节点,右侧会显示当前节点属性,直接修改style属性就能即时生效。这个能力在做移动端样式微调时非常实用,不用改代码、刷新、再截图。另外它的Network面板会聚合请求数量和总耗时,方便判断页面里哪个接口拖了后腿。有一次我做了一个长列表页,首屏接口和数据渲染都很顺利,但滑动时明显卡顿,用Eruda一查才发现某个像素图被重复加载了几十次。这类性能问题,光看页面表现很难定位,有工具就能节省大量时间。
一个小经验:Eruda默认面板高度可能太高,可以把panelAutoHeight设为false并指定maxHeightRatio,让它只占屏幕一半左右,既能看到页面,又能操作面板。多页面切换时,如果每个页面都初始化一遍,面板会闪一下,建议在入口文件统一初始化,并且设置session配置持久化,避免每次进来都要手动打开。
3.3 Spy-Debugger安装、代理配置与证书信任
Spy-Debugger是基于Node环境的命令行工具,使用前需要先确认电脑已安装Node。安装命令:
npm install -g spy-debugger启动时可以直接指定端口和业务地址:
spy-debugger -p 9888 -i 手机IP启动后终端会打印出PC的局域网IP和代理端口,把手机WiFi设置里的HTTP代理指到这个IP和端口。完成这一步,手机上访问任意HTTP页面,请求都会转发到PC端,控制页面里能看到对应的请求列表。
HTTPS页面如果要看到明文,必须在手机上安装并信任证书。Spy-Debugger会生成自己的根证书,控制页面里通常有证书下载入口。iOS和Android的安装信任路径不太一样,iOS系统默认在“设置-描述文件”里安装描述文件后,还必须到“证书信任设置”里打开完全信任开关,否则HTTPS请求会失败。Android系统需要根据版本不同,在“安全-加密与凭据-安装证书”或“CA证书”入口安装,部分系统还要在应用的网络配置里允许用户证书,否则App内WebView仍不信任。
证书安装成功后,在PC控制页面里就能看到HTTPS请求的完整明文,包括POST参数、Cookie、响应体。这个能力做接口联调非常方便,不用再去后端日志里翻参数。不过要提醒一点:证书只在调试期间使用,调试完一定要恢复手机的代理设置和移除证书,不然手机后续访问HTTPS会有安全隐患。
这里我踩过最深的坑是“安卓7以上版本”的差异。某次在真机App内调试HTTPS接口,代理和证书都装好了,浏览器页面可以解出明文,但App里的WebView请求还是失败。后来才发现是App网络配置默认不信任用户CA证书,需要单独在AndroidManifest或网络安全配置里加上信任。调试到这种问题时不要急着怀疑工具,先确认你的目标环境允不允许抓包。
3.4 日常调试的几个高频操作
实际调试中,除了看日志和抓包,还有几个动作我几乎每次都会用到。第一个是修改请求参数重新发送。在Spy-Debugger控制页面里,可以对某个请求做编辑和重放,方便验证后端对不同参数的响应。第二个是Network面板里的耗时时间线。如果某个接口首次加载特别慢,可以通过它区分是DNS、连接、还是响应体过大。第三个是在页面内模拟弱网,Eruda的Sensors面板和Spy-Debugger提供的命令行都可以设置网络限速,模拟2G/3G环境,不需要单独装弱网工具。
还有一个容易被忽略的操作:把手机屏幕投到PC上。Spy-Debugger的远程inspect可以截取手机屏幕,甚至远程点击,这比让同事拿着手机口述问题要高效得多。遇到页面白屏,可以在PC端控制页面直接执行location.reload(),看报错输出,基本就知道是脚本崩了还是接口返回异常。
我自己的日常节奏是:打开Eruda,先过滤一下error日志,再切到Network看耗时;如果发现某个请求异常,立刻去Spy-Debugger里看完整请求头和响应体。两个工具配合起来,前端报错和后端返回基本都能在几分钟内确认。
4. 常见问题与排查技巧实录
这部分整理的是我在实际项目中反复遇到的问题,有些有明确的解决方案,有些需要结合环境判断。写出来给大家做个参考。
4.1 页面工具不显示、按钮点不透
用vConsole或Eruda时最常遇到的是“页面里看不到悬浮按钮”。检查顺序是:脚本是否真的加载成功、初始化是否执行、是否被生产环境开关过滤掉。可以在PC模拟器的Console里手动执行window.vConsole或window.eruda,如果返回undefined,说明脚本没进来。另一个常见问题是工具按钮被页面上的元素遮挡,这时候打开工具的“拖动模式”,或者调整z-index配置,把面板层级抬高。
还有一次遇到Eruda在低版本WebView里打不开,是因为项目中用了高版本ES语法,低端机解析不了。解决方法是把调试脚本单独用ES5编译产物,或者用动态script加载并保留降级。这类问题往往跟工具本身无关,而是环境兼容问题,排查时先把工具脚本独立出来测,能少走很多弯路。
遇到过“按钮出来了但面板打开是白屏”的情况,多半是面板容器样式被全局CSS重置了。检查一下项目里是否写了类似*{margin:0;padding:0}或者对z-index做过统一覆盖,必要时可以在初始化配置里指定独立容器并加一个高优先级样式。调试工具得保证自己不被业务样式污染。
4.2 请求抓不到、证书不生效
Spy-Debugger抓不到请求,先确认手机代理是否设置成功:在手机上访问一个HTTP页面,看PC控制页面有没有请求记录。如果没有,检查手机和PC是否在同一网段、代理端口是否被防火墙拦截。常见原因是手机连接了不同WiFi,或者PC上有多个网卡导致IP绑定错误,尝试用-i参数指定手机实际网段对应的IP。
HTTPS请求抓不到或报证书错误,大部分是证书信任步骤不完整。iOS尤其要注意“证书完全信任”开关,只安装描述文件还不够。如果是Android高版本系统,许多App默认不信任用户CA证书,需要在网络配置或App内开启“允许用户证书”。如果正在调试的是某个App内嵌页面,代理要设置到系统级而不是仅浏览器,否则应用内部的HTTP库不走代理。
还有一个容易忽略的点:Spy-Debugger的代理只对设置了代理的客户端生效,如果App强制使用固定IP或者不读系统代理,就需要用透明代理方式绕开。这种场景建议换用独立的WiFi热点方案,把PC做成热点,手机连上热点后流量全部经过PC,抓包成功率会高很多。
4.3 真机远程调试连接不稳定怎么办
远程调试时最烦的就是连接断开。载体是局域网,无线信号不好,手机网络代理就会频繁失效。我通常的解决办法,是把PC和手机放在同一个房间,尽量靠近路由器;如果PC本身用的是无线网卡,建议改用有线网络,减少链路抖动。Spy-Debugger还可以设置超时时间和重连参数,出现断连时不必重启整个服务,只要手机代理重新指一下就行。
还有一个策略:调试线上问题时先抓包、后注入。如果线上页面不能随意加调试脚本,先用Spy-Debugger抓完整请求和响应,定位接口层问题;需要看页面内部状态时,再通过远程inspect临时执行脚本获取。这样可以把连接时间压缩到最短,减少断连风险。碰到页面反复崩溃的情况,记得把Spy-Debugger的日志级别调低,避免大量日志跨网络传输,反而把页面拖死。
最后分享一个我个人的习惯:不管用哪种调试工具,都一定把“生产环境不加载、测试环境默认开”这条规则固化成构建模板,并在每次发布前检查一遍产物里有没有调试面板的关键词。调试工具是给开发用的,流到用户手里就是事故。日常项目里,vConsole、Eruda和Spy-Debugger各有各的活儿,我现在的组合是Eruda做日常页面检查,Spy-Debugger做请求链路兜底,基本上覆盖了移动端开发里绝大多数调试场景。如果你刚接触移动端调试,建议从vConsole开始,成本最低,跑通流程后再上Eruda和Spy-Debugger,会顺很多。