H5 调试实战
H5 调试实战(二):Android WebView 白屏排查,从 Console 远程定位到 Mock 验证
白屏了
事情发生在一次活动 H5 压测。
测试在群里发了一段录屏:
「三星 S23,Android 14,微信里面打开活动页,点击『立即参与』之后页面白屏。」
比较奇怪的是,这不是完全打不开。
页面能够正常加载:
- 首页内容正常展示;
- 按钮可以点击;
- 点击后有 loading;
但是随后页面直接白屏。
iOS 正常,其他 Android 设备也正常。
这种问题第一反应通常会看几个方向:
- JavaScript 是否运行异常;
- 接口返回数据是否导致渲染失败;
- Android WebView 是否存在兼容问题。
先从网络层开始排查。
抓包正常,但页面还是挂了
先看接口请求。
POST /api/campaign/join
返回:
200 OK
请求参数正常。
响应数据结构也符合预期。
至少可以确定:接口没有直接失败。
但是页面依然白屏。
这类问题比较麻烦:请求成功了,页面也加载了,但某一步执行失败。
如果没有运行时日志,只能靠猜。
vConsole 和 Remote Debug 都不太适合这个场景
通常 H5 页面调试,第一个想到的是 vConsole。
但是这个活动页面已经上线,测试环境无法直接重新打包注入 vConsole。
而且问题只发生在特定 Android 设备。
Chrome Remote Debug 也尝试过:
chrome://inspect
可以连接 WebView。
但是问题发生在点击按钮之后。刷新页面时错误已经不存在。
另外:
- WebView 调试开关需要客户端支持;
- USB 连接有环境要求;
- 线上版本不方便反复调整。
现在的问题是:手机里的微信 WebView 已经出现异常,但我需要看到它真实运行时的状态。
先拿到线上 WebView 的 Console
测试机通过代理连接 DevPeek。
完成:
- 安装 HTTPS 证书;
- 配置代理;
- 开启目标域名 SSL 解密。
完整前置清单见 移动端网页调试;若预览区停在「等待设备连接」,先过一遍 常见问题。
然后在 DevPeek 调试 Tab 中选择对应设备,测试重新打开活动页面。
控制台马上出现了一条异常:
Uncaught TypeError:
e.isIntersecting is not a function
at IntersectionObserver polyfill
(chunk-vendors.js:1847)

真机控制台输出实时推送到调试面板。
问题方向开始明确。
原因:polyfill 覆盖了 Android 原生实现
这里涉及 IntersectionObserver。
Android 14 的 WebView 已经支持这个 API。
但是项目里仍然加载了一份旧版 polyfill,而这份 polyfill 又覆盖了浏览器原生实现。
于是页面实际运行的不是 native IntersectionObserver,而是 polyfill 版本。两套实现之间存在兼容差异。
继续通过 Console 远程执行几行代码确认:
navigator.userAgent.match(/Android\s([\d.]+)/)?.[1];
// "14" ——确认 Android 版本
typeof IntersectionObserver;
// "function" ——确认 API 存在
IntersectionObserver.toString().includes("native code");
// false ——确认当前实现不是浏览器原生版本
定位完成。
问题定位了,但测试还没结束
前端开始修复 polyfill。
但是压测窗口还在继续。
测试还需要确认:如果接口返回异常状态,页面的降级逻辑是否正常。
例如:
- 活动已结束;
- 用户没有权限;
- 活动库存不足。
这些场景不能每次都等后端配合,所以需要模拟接口响应。
用 Mock 验证异常场景
在 DevPeek 抓包列表找到 POST /api/campaign/join。
创建 Mock 规则。
匹配条件:
- URL 包含
campaign/join - Method 为 POST
修改响应:
{
"code": 10086,
"message": "活动已结束"
}
保存并启用。

Mock 规则保存即生效,不需要重启代理。
测试重新点击按钮。
这次页面没有白屏,而是正常显示「活动已结束」。
降级逻辑验证通过。
如果继续测试其他错误场景,例如:
{
"code": 10010,
"message": "当前活动不可用"
}
可以继续修改 Mock 响应,快速验证不同异常状态下的页面表现。
整个过程不需要:
- 修改后端接口;
- 等待接口发布;
- 重新打包 H5。
Mock 规则是持久化的,关掉 DevPeek 再打开仍然有效。联调结束后记得禁用或删除临时规则,避免影响后续抓包。
整个排查过程
这次的问题最终定位链路:
点击按钮
↓
抓包确认接口正常返回 200
↓
Console 获取 WebView 运行时异常
↓
远程 eval 确认 polyfill 覆盖问题
↓
修复方案确认
↓
Mock 模拟异常接口
↓
验证页面降级逻辑
整个过程中,没有重新打包 H5,也没有要求客户端开启调试模式。
为什么这次排查比较顺
以前遇到类似问题,通常需要几个工具配合:
- 抓包工具确认请求;
- vConsole 查看运行日志;
- 修改接口响应测试异常流程。
每个工具都能解决一部分问题。
但排查过程中经常会遇到:
- 刚才那个错误日志在哪里?
- 这个接口刚才返回了什么?
- Mock 修改之后手机有没有重新触发?
问题信息分散在不同工具里。
这次所有信息都在同一条调试链路中:
Network
↓
Console
↓
Mock
↓
真实设备页面
对于移动端 H5 调试来说,减少工具切换,本身就是减少排查成本。
一些实际限制
当然,Console 和 Mock 也不是万能的。完整边界见 移动端网页调试 文档。
1. 页面已经彻底崩溃
例如无限循环、栈溢出、主线程阻塞——这种情况下调试脚本可能也无法注入。需要先从资源加载和网络请求方向排查。
2. iframe 页面
Console 默认运行在当前页面上下文。如果问题发生在 iframe 内,需要单独打开 iframe 地址调试。
3. Mock 不一定能拦截所有请求
Mock 依赖代理链路。Service Worker 缓存、客户端原生网络层拦截、某些特殊 WebView 内核行为可能绕过。需要确认请求确实经过代理。
4. 远程 eval 的执行环境
远程执行脚本和页面共享上下文。简单检查没有问题,但不要直接执行大量遍历 IndexedDB 或长时间计算任务,建议使用异步方式。
下一篇
《H5 调试实战(三):待整理》——继续记录一些真实移动端 H5 联调案例。
如果你也经常遇到接口正常但是页面异常、Android WebView 兼容问题、线上 H5 无法直接调试,欢迎 下载 DevPeek 试用,或到 GitHub Discussions 聊聊。