[{"data":1,"prerenderedAt":36},["ShallowReactive",2],{"case-h5-debug-console-mock-zh":3,"blog-list-zh":13},{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9,"series":10,"seriesOrder":11,"html":12},"h5-debug-console-mock","H5 调试实战（二）：Android WebView 白屏排查，从 Console 远程定位到 Mock 验证","活动 H5 在部分 Android 设备中点击按钮后白屏，请求全部 200 却没有页面反馈。通过 DevPeek Console 获取线上 WebView 运行日志，远程 eval 确认 polyfill 覆盖问题，再使用 Mock 验证异常状态下的降级页面。","2026-07-13",true,"H5 调试实战第二篇：排查 Android WebView 白屏问题。通过 Console 远程调试定位 JavaScript polyfill 兼容问题，并结合 Mock 验证接口异常场景下的页面降级逻辑。","h5-debug",2,"\u003Ch2>白屏了\u003C\u002Fh2>\n\u003Cp>事情发生在一次活动 H5 压测。\u003C\u002Fp>\n\u003Cp>测试在群里发了一段录屏：\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>「三星 S23，Android 14，微信里面打开活动页，点击『立即参与』之后页面白屏。」\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>比较奇怪的是，这不是完全打不开。\u003C\u002Fp>\n\u003Cp>页面能够正常加载：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>首页内容正常展示；\u003C\u002Fli>\n\u003Cli>按钮可以点击；\u003C\u002Fli>\n\u003Cli>点击后有 loading；\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>但是随后页面直接白屏。\u003C\u002Fp>\n\u003Cp>iOS 正常，其他 Android 设备也正常。\u003C\u002Fp>\n\u003Cp>这种问题第一反应通常会看几个方向：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>JavaScript 是否运行异常；\u003C\u002Fli>\n\u003Cli>接口返回数据是否导致渲染失败；\u003C\u002Fli>\n\u003Cli>Android WebView 是否存在兼容问题。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>先从网络层开始排查。\u003C\u002Fp>\n\u003Ch2>抓包正常，但页面还是挂了\u003C\u002Fh2>\n\u003Cp>先看接口请求。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>POST \u002Fapi\u002Fcampaign\u002Fjoin\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>返回：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>200 OK\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>请求参数正常。\u003C\u002Fp>\n\u003Cp>响应数据结构也符合预期。\u003C\u002Fp>\n\u003Cp>至少可以确定：接口没有直接失败。\u003C\u002Fp>\n\u003Cp>但是页面依然白屏。\u003C\u002Fp>\n\u003Cp>这类问题比较麻烦：请求成功了，页面也加载了，但某一步执行失败。\u003C\u002Fp>\n\u003Cp>如果没有运行时日志，只能靠猜。\u003C\u002Fp>\n\u003Ch2>vConsole 和 Remote Debug 都不太适合这个场景\u003C\u002Fh2>\n\u003Cp>通常 H5 页面调试，第一个想到的是 vConsole。\u003C\u002Fp>\n\u003Cp>但是这个活动页面已经上线，测试环境无法直接重新打包注入 vConsole。\u003C\u002Fp>\n\u003Cp>而且问题只发生在特定 Android 设备。\u003C\u002Fp>\n\u003Cp>Chrome Remote Debug 也尝试过：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>chrome:\u002F\u002Finspect\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>可以连接 WebView。\u003C\u002Fp>\n\u003Cp>但是问题发生在点击按钮之后。刷新页面时错误已经不存在。\u003C\u002Fp>\n\u003Cp>另外：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>WebView 调试开关需要客户端支持；\u003C\u002Fli>\n\u003Cli>USB 连接有环境要求；\u003C\u002Fli>\n\u003Cli>线上版本不方便反复调整。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>现在的问题是：手机里的微信 WebView 已经出现异常，但我需要看到它真实运行时的状态。\u003C\u002Fp>\n\u003Ch2>先拿到线上 WebView 的 Console\u003C\u002Fh2>\n\u003Cp>测试机通过代理连接 DevPeek。\u003C\u002Fp>\n\u003Cp>完成：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>安装 HTTPS 证书；\u003C\u002Fli>\n\u003Cli>配置代理；\u003C\u002Fli>\n\u003Cli>开启目标域名 SSL 解密。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>完整前置清单见 \u003Ca href=\"\u002Fdocs\u002Fdebug-replay\u002F\">移动端网页调试\u003C\u002Fa>；若预览区停在「等待设备连接」，先过一遍 \u003Ca href=\"\u002Fdocs\u002Ffaq\u002F\">常见问题\u003C\u002Fa>。\u003C\u002Fp>\n\u003Cp>然后在 DevPeek \u003Cstrong>调试\u003C\u002Fstrong> Tab 中选择对应设备，测试重新打开活动页面。\u003C\u002Fp>\n\u003Cp>控制台马上出现了一条异常：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Uncaught TypeError:\ne.isIntersecting is not a function\n\nat IntersectionObserver polyfill\n(chunk-vendors.js:1847)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fdebug_console_eval.png\" alt=\"DevPeek 调试 Console：报错与远程 eval\">\u003C\u002Fp>\n\u003Cp>\u003Cem>真机控制台输出实时推送到调试面板。\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>问题方向开始明确。\u003C\u002Fp>\n\u003Ch2>原因：polyfill 覆盖了 Android 原生实现\u003C\u002Fh2>\n\u003Cp>这里涉及 \u003Ccode>IntersectionObserver\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Cp>Android 14 的 WebView 已经支持这个 API。\u003C\u002Fp>\n\u003Cp>但是项目里仍然加载了一份旧版 polyfill，而这份 polyfill 又覆盖了浏览器原生实现。\u003C\u002Fp>\n\u003Cp>于是页面实际运行的不是 native \u003Ccode>IntersectionObserver\u003C\u002Fcode>，而是 polyfill 版本。两套实现之间存在兼容差异。\u003C\u002Fp>\n\u003Cp>继续通过 Console 远程执行几行代码确认：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-javascript\">navigator.userAgent.match(\u002FAndroid\\s([\\d.]+)\u002F)?.[1];\n\u002F\u002F &quot;14&quot;  ——确认 Android 版本\n\ntypeof IntersectionObserver;\n\u002F\u002F &quot;function&quot;  ——确认 API 存在\n\nIntersectionObserver.toString().includes(&quot;native code&quot;);\n\u002F\u002F false  ——确认当前实现不是浏览器原生版本\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>定位完成。\u003C\u002Fp>\n\u003Ch2>问题定位了，但测试还没结束\u003C\u002Fh2>\n\u003Cp>前端开始修复 polyfill。\u003C\u002Fp>\n\u003Cp>但是压测窗口还在继续。\u003C\u002Fp>\n\u003Cp>测试还需要确认：如果接口返回异常状态，页面的降级逻辑是否正常。\u003C\u002Fp>\n\u003Cp>例如：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>活动已结束；\u003C\u002Fli>\n\u003Cli>用户没有权限；\u003C\u002Fli>\n\u003Cli>活动库存不足。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>这些场景不能每次都等后端配合，所以需要模拟接口响应。\u003C\u002Fp>\n\u003Ch2>用 Mock 验证异常场景\u003C\u002Fh2>\n\u003Cp>在 DevPeek 抓包列表找到 \u003Ccode>POST \u002Fapi\u002Fcampaign\u002Fjoin\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Cp>创建 Mock 规则。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>匹配条件：\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>URL 包含 \u003Ccode>campaign\u002Fjoin\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>Method 为 POST\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cstrong>修改响应：\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">{\n  &quot;code&quot;: 10086,\n  &quot;message&quot;: &quot;活动已结束&quot;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>保存并启用。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fmock_wizard_auto_response.png\" alt=\"DevPeek Mock 规则编辑：匹配条件与响应篡改\">\u003C\u002Fp>\n\u003Cp>\u003Cem>Mock 规则保存即生效，不需要重启代理。\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>测试重新点击按钮。\u003C\u002Fp>\n\u003Cp>这次页面没有白屏，而是正常显示「活动已结束」。\u003C\u002Fp>\n\u003Cp>降级逻辑验证通过。\u003C\u002Fp>\n\u003Cp>如果继续测试其他错误场景，例如：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">{\n  &quot;code&quot;: 10010,\n  &quot;message&quot;: &quot;当前活动不可用&quot;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>可以继续修改 Mock 响应，快速验证不同异常状态下的页面表现。\u003C\u002Fp>\n\u003Cp>整个过程不需要：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>修改后端接口；\u003C\u002Fli>\n\u003Cli>等待接口发布；\u003C\u002Fli>\n\u003Cli>重新打包 H5。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Mock 规则是持久化的，关掉 DevPeek 再打开仍然有效。联调结束后记得禁用或删除临时规则，避免影响后续抓包。\u003C\u002Fp>\n\u003Ch2>整个排查过程\u003C\u002Fh2>\n\u003Cp>这次的问题最终定位链路：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>点击按钮\n    ↓\n抓包确认接口正常返回 200\n    ↓\nConsole 获取 WebView 运行时异常\n    ↓\n远程 eval 确认 polyfill 覆盖问题\n    ↓\n修复方案确认\n    ↓\nMock 模拟异常接口\n    ↓\n验证页面降级逻辑\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>整个过程中，没有重新打包 H5，也没有要求客户端开启调试模式。\u003C\u002Fp>\n\u003Ch2>为什么这次排查比较顺\u003C\u002Fh2>\n\u003Cp>以前遇到类似问题，通常需要几个工具配合：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>抓包工具确认请求；\u003C\u002Fli>\n\u003Cli>vConsole 查看运行日志；\u003C\u002Fli>\n\u003Cli>修改接口响应测试异常流程。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>每个工具都能解决一部分问题。\u003C\u002Fp>\n\u003Cp>但排查过程中经常会遇到：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>刚才那个错误日志在哪里？\u003C\u002Fli>\n\u003Cli>这个接口刚才返回了什么？\u003C\u002Fli>\n\u003Cli>Mock 修改之后手机有没有重新触发？\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>问题信息分散在不同工具里。\u003C\u002Fp>\n\u003Cp>这次所有信息都在同一条调试链路中：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Network\n   ↓\nConsole\n   ↓\nMock\n   ↓\n真实设备页面\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>对于移动端 H5 调试来说，减少工具切换，本身就是减少排查成本。\u003C\u002Fp>\n\u003Ch2>一些实际限制\u003C\u002Fh2>\n\u003Cp>当然，Console 和 Mock 也不是万能的。完整边界见 \u003Ca href=\"\u002Fdocs\u002Fdebug-replay\u002F\">移动端网页调试\u003C\u002Fa> 文档。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>1. 页面已经彻底崩溃\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>例如无限循环、栈溢出、主线程阻塞——这种情况下调试脚本可能也无法注入。需要先从资源加载和网络请求方向排查。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>2. iframe 页面\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Console 默认运行在当前页面上下文。如果问题发生在 iframe 内，需要单独打开 iframe 地址调试。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>3. Mock 不一定能拦截所有请求\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Mock 依赖代理链路。Service Worker 缓存、客户端原生网络层拦截、某些特殊 WebView 内核行为可能绕过。需要确认请求确实经过代理。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>4. 远程 eval 的执行环境\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>远程执行脚本和页面共享上下文。简单检查没有问题，但不要直接执行大量遍历 IndexedDB 或长时间计算任务，建议使用异步方式。\u003C\u002Fp>\n\u003Ch2>下一篇\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>《H5 调试实战（三）：待整理》\u003C\u002Fstrong>——继续记录一些真实移动端 H5 联调案例。\u003C\u002Fp>\n\u003Chr>\n\u003Cp>如果你也经常遇到接口正常但是页面异常、Android WebView 兼容问题、线上 H5 无法直接调试，欢迎 \u003Ca href=\"\u002F\">下载 DevPeek 试用\u003C\u002Fa>，或到 \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FGYPengDev\u002Fdevpeek\u002Fdiscussions\">GitHub Discussions\u003C\u002Fa> 聊聊。\u003C\u002Fp>\n\u003Ch2>相关文档\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"\u002Fdocs\u002Fdebug-replay\u002F\">移动端网页调试\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fdocs\u002Fmock\u002F\">Mock 规则\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fdocs\u002Fcapture\u002F\">抓包界面与请求详情\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fdocs\u002Fproxy-ssl\u002F\">代理与 SSL 证书\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fdocs\u002Ffaq\u002F\">常见问题\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>系列文章\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"\u002Fblog\u002Fwechat-h5-storage-debug\u002F\">H5 调试实战（一）：微信 H5 localStorage 调试，在电脑上修改真机缓存\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n",{"items":14},[15,16,23,30],{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9,"series":10,"seriesOrder":11},{"slug":17,"title":18,"summary":19,"date":20,"featured":8,"seoDescription":21,"series":10,"seriesOrder":22},"wechat-h5-storage-debug","H5 调试实战（一）：微信 H5 localStorage 调试，在电脑上修改真机缓存","微信 H5 换测试号后头像仍显示旧用户，抓包确认接口正常，却定位到 localStorage 遗留旧数据。本文记录一次真实联调过程，以及如何在电脑上查看、修改微信 WebView 的 localStorage、sessionStorage 和 IndexedDB。","2026-07-11","微信 H5 调试实战：通过真实案例定位 localStorage、sessionStorage、IndexedDB 导致的数据缓存问题，对比 vConsole、Remote Debug 等方案，介绍真机 WebView 调试思路。",1,{"slug":24,"title":25,"summary":26,"date":27,"featured":8,"seoDescription":28,"series":29,"seriesOrder":11},"why-we-built-devpeek-h5-debug","我们为什么做 DevPeek（二）：App 里那页 H5，在电脑上也能对着查","登录接口用参数转换啃下来了，活动页 H5 却在 App WebView 里才崩。真机 remote debug 折腾一圈，DOM 和抓包还是两拨窗口——于是把镜像和自研调试面板收进 DevPeek。","2026-07-10","DevPeek 起源系列第二篇：App 内嵌 H5 只在真机出问题、remote debug 与抓包割裂的联调痛点，以及调试 Tab 如何把页面镜像到电脑并用自研面板查 DOM、Console 与 Network。","origin",{"slug":31,"title":32,"summary":33,"date":34,"featured":8,"seoDescription":35,"series":29,"seriesOrder":22},"why-we-built-devpeek","我们为什么做 DevPeek（一）：HTTPS 解密了，Body 还是天书","版本日前那晚，TLS 早就解开了，改请求里一个字段却还要翻脚本加解密。于是萌生做一个把业务加解密收进代理的工具——DevPeek 从这儿开始。","2026-07-09","DevPeek 起源系列第一篇：联调时请求体加解密的手工折腾，以及为什么先做一款把业务加解密收进代理的工具。",1783946169608]