ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

vConsole+MCP+WebSocket:让AI直接读取H5运行时日志的调试方案

vConsole+MCP+WebSocket:让AI直接读取H5运行时日志的调试方案 1. 移动端调试的真实困境与破局思路做过 H5 开发的人都有一个共同的痛在 PC 浏览器上跑得好好的页面一放到手机里就各种诡异问题。白屏、接口 404、样式错位、点击无响应这些在 Chrome DevTools 里一眼就能定位的问题到了真机上就变成了黑盒。你只能靠alert大法、靠猜、靠反复改代码重新部署来试错效率低到令人发指。传统的解决方案是引入 vConsole 这类移动端调试面板。它确实解决了在手机上看日志的问题但新的麻烦随之而来日志是给人眼看的不是给 AI 看的。当你想让 AI 帮你分析一个线上 bug 时你只能手动截图、复制粘贴日志、描述现象AI 拿到的信息永远是残缺的、滞后的。更别提那些动态刷新的请求列表、需要展开才能看到的对象结构截图根本传递不了完整信息。这个项目的核心思路就是打通vConsole 和 AI 之间的数据通道。通过 MCPModel Context Protocol协议把 vConsole 捕获的日志、网络请求、存储数据等运行时信息以结构化的方式暴露给 AI 工具。AI 不再是盲人摸象而是能直接读取 H5 页面的实时运行状态像一位坐在你旁边的资深工程师一样看着日志帮你定位问题。这套方案适合几类人一是经常和移动端 H5 打交道的前端开发尤其是做直播、电商、活动页这类交互复杂的场景二是正在探索AI 辅助开发工作流的工程师想看看 MCP 在实际项目中怎么落地三是对WebSocket 实时通信和调试工具链感兴趣的技术爱好者。哪怕你之前没接触过 MCP只要会基本的 H5 开发跟着思路走也能理解整套机制。2. 核心架构拆解vConsole、MCP 与 WebSocket 如何协同2.1 为什么是这三个技术组合先说说为什么选 vConsole 作为数据源。市面上移动端调试工具不少比如 Eruda、Chii 等但 vConsole 的生态最成熟微信官方文档都推荐它社区插件丰富而且它的日志拦截机制做得比较干净——它通过重写console对象的方法来捕获日志通过拦截XMLHttpRequest和fetch来捕获请求这种无侵入的设计意味着你不需要改动业务代码就能拿到数据。MCP 的选择则是顺应了当前 AI 工具链的趋势。MCP 本质上是一套标准化的协议让 AI 客户端比如各种支持 MCP 的编辑器、命令行工具能够以统一的方式访问外部数据源和工具。你可以把它理解成AI 世界的 USB 接口——只要你的服务实现了 MCP 协议任何支持 MCP 的 AI 都能直接调用不需要为每个 AI 平台单独适配。这比传统的写个 API 让 AI 调要规范得多因为 MCP 定义了资源Resource、工具Tool、提示Prompt的标准结构AI 知道怎么发现和调用这些能力。WebSocket 则是连接 vConsole 和 MCP 服务端的桥梁。为什么不用 HTTP 轮询因为调试场景下日志是高频、实时、双向的。页面每产生一条日志、每发出一个请求都需要立刻推送到 MCP 服务端反过来AI 可能想主动触发某个操作比如清空日志、执行一段代码也需要实时下发指令。WebSocket 的全双工特性正好匹配这个需求而且它比轮询节省大量连接开销在移动端网络环境下更稳定。2.2 整体数据流向整个链路可以这样理解H5 页面加载 vConsole 和一个自定义的桥接插件插件负责监听 vConsole 的数据变化一旦有新日志或请求产生插件通过 WebSocket 把数据推送到本地运行的 MCP 服务端MCP 服务端把这些数据缓存起来并以 MCP Resource 的形式暴露出去AI 客户端通过 MCP 协议读取这些资源就能看到页面的实时状态。反向的流程是AI 通过 MCP Tool 发起指令比如获取最近 50 条日志或清空网络请求记录MCP 服务端通过 WebSocket 把指令转发给页面端的桥接插件插件执行后把结果回传。这样就形成了一个完整的闭环。这里有个关键设计点数据缓存策略。日志和请求是源源不断产生的不可能无限缓存。常见的做法是维护一个固定长度的环形缓冲区比如保留最近 500 条日志和 200 条请求。当 AI 请求数据时返回的是这个缓冲区里的快照。这样既保证了 AI 能看到足够的历史上下文又不会让内存无限增长。缓冲区大小的选择需要权衡太小会丢失关键信息太大则占用内存且传输慢。根据经验500 条日志对于大多数调试场景已经足够如果是长时间运行的页面可以适当调大到 1000 条。2.3 与纯截图方案的对比很多人会问我直接截图给 AI 看不行吗短期看确实可以但有几个硬伤。第一截图是静态的AI 看不到日志的时间顺序和因果关系比如某条错误日志是在哪个请求之后产生的截图里体现不出来。第二截图里的对象是折叠的[Object object]这种信息 AI 完全无法解析而结构化数据可以完整传递。第三截图无法交互AI 不能主动展开某个请求看详情也不能过滤出特定类型的日志。第四截图有隐私风险页面上可能有用户信息、token 等敏感内容而结构化数据可以在传输前做脱敏处理。所以这套方案的价值不在于能看日志而在于让 AI 以可编程的方式理解日志。这是质的区别。3. 从零搭建环境准备与核心模块实现3.1 页面端桥接插件的编写页面端是整个链路的数据源头核心是一个 vConsole 插件。vConsole 提供了插件机制你可以通过VConsole.VConsolePlugin来注册自定义插件。但这里有个技巧我们不需要真的在 vConsole 面板上显示什么 UI只需要借用它的生命周期钩子来挂载我们的监听逻辑。// bridge-plugin.js class BridgePlugin { constructor(vConsole) { this.vConsole vConsole; this.ws null; this.logBuffer []; this.requestBuffer []; this.maxLogs 500; this.maxRequests 200; this.init(); } init() { this.connectWebSocket(); this.hookConsole(); this.hookNetwork(); } connectWebSocket() { this.ws new WebSocket(ws://127.0.0.1:8765); this.ws.onopen () { this.send({ type: handshake, payload: { ua: navigator.userAgent } }); }; this.ws.onmessage (e) { const msg JSON.parse(e.data); this.handleCommand(msg); }; this.ws.onclose () { setTimeout(() this.connectWebSocket(), 2000); }; } }这里有几个实操要点。第一WebSocket 地址用127.0.0.1而不是localhost因为在某些移动端浏览器里localhost解析可能有问题127.0.0.1更可靠。第二断线重连是必须的移动端网络切换频繁没有重连机制的话链路很容易断。第三握手时把 User-Agent 传过去MCP 服务端可以据此判断设备类型后续做针对性处理。3.2 日志拦截的实现细节拦截console不能简单地覆盖方法因为 vConsole 本身也做了拦截。正确的做法是在 vConsole 初始化之后再包装一层或者直接监听 vConsole 的数据变化。更稳妥的方式是利用 vConsole 的事件机制但不同版本 API 有差异所以实践中常用的是二次包装hookConsole() { const methods [log, info, warn, error, debug]; methods.forEach((method) { const original console[method]; console[method] (...args) { original.apply(console, args); this.pushLog({ level: method, args: args.map((a) this.serialize(a)), timestamp: Date.now(), }); }; }); } serialize(value) { if (value null || value undefined) return String(value); if (typeof value object) { try { return JSON.parse(JSON.stringify(value)); } catch (e) { return [Circular or Unserializable]; } } return value; }serialize这个函数是重点。日志里经常有循环引用的对象直接JSON.stringify会抛异常所以要用 try-catch 兜底。另外对于 DOM 节点、函数这类无法序列化的值要给出明确的占位符而不是让整个日志推送失败。我踩过的坑是早期版本没做这个处理结果页面里一旦打印了 DOM 元素整个 WebSocket 推送就崩了日志全丢。3.3 网络请求的捕获与结构化请求捕获比日志复杂因为要处理XMLHttpRequest和fetch两套 API还要区分请求发起、响应返回、错误等不同阶段。核心思路是包装原生方法在关键节点插入回调hookNetwork() { const originalFetch window.fetch; window.fetch async (...args) { const startTime Date.now(); const requestInfo this.parseRequestArgs(args); try { const response await originalFetch.apply(window, args); const clone response.clone(); clone.text().then((body) { this.pushRequest({ ...requestInfo, status: response.status, duration: Date.now() - startTime, responseBody: this.truncate(body, 10000), }); }); return response; } catch (err) { this.pushRequest({ ...requestInfo, status: error, error: err.message, duration: Date.now() - startTime, }); throw err; } }; }这里有个关键细节response.clone()。fetch 的响应体只能被读取一次如果不 clone 就直接读业务代码就拿不到数据了。clone 之后一份给业务用一份给我们解析。另外响应体要做截断超过 10KB 的内容只保留头部否则大文件响应会把 WebSocket 撑爆。truncate函数要保留足够的信息用于调试比如 JSON 结构的前几个字段同时标注内容已截断。对于XMLHttpRequest思路类似但要在open、send、onreadystatechange等钩子上做文章。这里不展开全部代码核心是记录请求方法、URL、请求头、请求体、响应状态、响应体、耗时这几个字段。3.4 MCP 服务端的资源与工具定义MCP 服务端是整个方案的中枢它要同时处理两件事接收页面推送的数据以及响应 AI 客户端的请求。用 Node.js 实现的话可以基于官方的 MCP SDK。核心是定义几个 Resource 和 Tool类型名称作用Resourceh5://logs返回当前缓冲区内的日志列表Resourceh5://requests返回当前缓冲区内的请求列表Resourceh5://storage返回 localStorage/sessionStorage 快照Toolclear_logs清空日志缓冲区Toolclear_requests清空请求缓冲区Tooleval_js在页面端执行一段 JS 并返回结果Resource 和 Tool 的区别在于Resource 是只读的数据AI 读取后作为上下文Tool 是可执行的动作AI 调用后会改变状态或产生副作用。把日志和请求设计成 Resource是因为 AI 主要是看它们把清空和执行 JS 设计成 Tool是因为这些是主动操作。eval_js这个 Tool 特别有用。有时候 AI 想验证一个猜想比如页面上某个元素是否存在它可以直接执行document.querySelector(.target)并拿到结果而不需要你手动去查。当然这个功能有安全风险所以实践中要加白名单或确认机制不能让它执行任意代码。4. 实操全流程从启动到 AI 读取日志4.1 本地服务启动与页面接入第一步是启动 MCP 服务端。假设你已经用 Node.js 写好了服务通常是通过命令行启动node mcp-server.js --port 8765 --mcp-port 3000这里有两个端口8765是 WebSocket 端口给页面端连接3000是 MCP 服务端口给 AI 客户端连接。分开端口是为了职责清晰也方便排查问题——如果页面连不上你只需要检查 8765如果 AI 读不到数据只需要检查 3000。第二步是在 H5 页面里引入 vConsole 和桥接插件。推荐用 CDN 引入 vConsole桥接插件则内联或单独打包script srchttps://cdn.jsdelivr.net/npm/vconsolelatest/dist/vconsole.min.js/script script src./bridge-plugin.js/script script var vConsole new window.VConsole(); new BridgePlugin(vConsole); /script注意加载顺序vConsole 必须先初始化桥接插件才能拿到 vConsole 实例。如果你的页面是 SPA要在入口文件里做这件事确保只初始化一次。重复初始化会导致日志重复推送AI 看到的日志会翻倍非常干扰判断。4.2 AI 客户端的 MCP 配置不同的 AI 客户端配置方式不同但核心都是告诉它有一个 MCP 服务在 3000 端口。以常见的配置文件为例通常是这样{ mcpServers: { h5-debugger: { url: http://127.0.0.1:3000/sse, description: H5 页面实时调试数据源 } } }配置完成后AI 客户端会通过 SSEServer-Sent Events或 stdio 与服务端建立连接然后自动发现可用的 Resource 和 Tool。你可以在 AI 的对话里直接说读取 h5://logs 看看最近的错误日志它就会去拉取数据。这里有个实操心得先手动验证链路再接入 AI。在配置 AI 之前用curl或 Postman 直接请求 MCP 服务端的接口确认能拿到数据。如果这一步就失败说明是服务端或页面端的问题跟 AI 无关。我见过太多人一上来就配 AI结果排查半天发现是页面根本没连上 WebSocket。4.3 一次完整的调试实战假设页面在手机上出现了点击按钮无反应的问题。传统流程是你打开 vConsole翻日志看有没有报错看请求有没有发出。现在换成 AI 辅助流程你先在 AI 对话里说读取 h5://logs 和 h5://requests帮我分析为什么点击按钮没反应。AI 会拉取数据然后可能回复最近 10 条日志里有一条TypeError: Cannot read property id of undefined发生在handleClick函数中同时请求列表里没有对应的接口调用说明错误发生在请求发出之前。这个分析过程AI 是基于真实数据做的不是猜的。你可以继续追问把那条错误日志的完整堆栈给我。AI 会从 Resource 里提取详细信息。如果堆栈不够你还可以让 AI 调用eval_js去页面里查更多上下文。整个过程中你不需要截图、不需要复制粘贴、不需要描述现象。AI 直接看见了页面的运行状态。这就是这套方案的核心价值。4.4 参数调优与性能考量缓冲区大小、推送频率、序列化深度这几个参数直接影响体验。缓冲区太小AI 看不到历史太大内存和传输都有压力。推送频率太高WebSocket 消息密集移动端可能卡顿太低日志有延迟AI 分析时可能拿到旧数据。我的经验值是日志缓冲区 500 条、请求缓冲区 200 条、推送做 100ms 的节流throttle。节流的实现是维护一个待推送队列每 100ms 批量发送一次而不是每条日志都发一次。这样既保证了实时性最多延迟 100ms又大幅降低了消息数量。序列化深度建议限制在 3 层超过的用[Deep Object]占位避免深层嵌套对象把消息撑大。5. 踩坑记录与常见问题速查5.1 连接类问题页面连不上 WebSocket是最常见的问题。排查顺序是先确认 MCP 服务端是否启动、端口是否被占用再确认页面里的 WebSocket 地址是否正确注意ws://前缀不能少然后看手机和电脑是否在同一网络下如果服务跑在电脑上、页面在手机上127.0.0.1是连不通的要用电脑的局域网 IP。这一点很多人会忽略以为127.0.0.1万能其实它只在本机有效。连接频繁断开通常是移动端浏览器在后台时会挂起 WebSocket。解决办法是加心跳机制客户端每隔 30 秒发一个 ping服务端回 pong超时没收到就重连。心跳间隔不能太短否则耗电也不能太长否则断线发现不及时。30 秒是个比较平衡的值。5.2 数据类问题日志重复推送多半是因为桥接插件被初始化了多次。检查你的代码确保new BridgePlugin()只执行一次。如果是 SPA路由切换时不要重复初始化。请求体或响应体丢失通常是序列化失败导致的。检查serialize函数是否处理了循环引用、Blob、FormData 等特殊类型。FormData 不能直接 JSON 序列化要遍历 entries 转成普通对象。AI 读到的数据是旧的可能是缓冲区满了之后新数据覆盖了旧数据而 AI 读的是快照。这种情况要么调大缓冲区要么在读取前先清空让 AI 拿到最新数据。5.3 常见问题速查表现象可能原因解决方向页面连不上地址错误/网络不通/端口占用检查 ws 地址、局域网 IP、端口连接频繁断后台挂起/无心跳加心跳机制、断线重连日志重复插件多次初始化确保只初始化一次请求体丢失序列化失败处理特殊类型、加 try-catchAI 读不到数据MCP 配置错误先用 curl 验证服务端数据延迟大推送频率低/缓冲区小调节流参数、调大缓冲区5.4 几个独家避坑技巧第一给日志加来源标记。如果你的页面有多个模块日志混在一起很难区分。可以在推送时带上模块名或页面路径AI 分析时能更快定位。第二敏感信息脱敏。日志和请求里可能有 token、手机号、身份证号。在推送前做一层正则替换把敏感字段替换成***。这不仅是安全问题也能避免 AI 被无关信息干扰。第三保留原始时间戳。不要用服务端接收时间要用页面端产生时间。因为网络传输有延迟服务端时间会失真。时间戳对于分析哪个请求先发、哪个日志后出至关重要。第四给 AI 明确的读取指令。不要只说看看日志要说读取最近 50 条 error 级别的日志和最近 20 条失败的请求。指令越具体AI 返回的结果越精准也越省 token。6. 扩展玩法这套思路还能怎么用6.1 接入更多数据源vConsole 只是数据源之一。同样的桥接思路可以接入 Performance API 拿到页面性能指标接入window.onerror拿到全局错误接入 Storage 事件拿到本地存储变化。把这些数据都通过 WebSocket 推送到 MCP 服务端AI 就能获得一个全息的页面视图。比如你可以问 AI页面首屏加载慢帮我看看是哪个资源拖后腿了。AI 结合 Performance 数据和请求列表能直接给出答案。6.2 反向控制与自动化目前主要是AI 读数据反过来也可以AI 写指令。比如让 AI 根据日志分析结果自动执行一段修复代码并验证效果。这在自动化测试场景下特别有用AI 发现某个断言失败自动调用eval_js去查 DOM 状态然后生成修复建议。当然自动执行代码有风险建议在测试环境用生产环境只读不写。6.3 多页面聚合如果一个项目有多个 H5 页面比如直播间的不同 tab可以让每个页面都连同一个 MCP 服务端服务端按页面标识区分数据。AI 就能跨页面分析问题比如用户在 A 页面点击后跳转到 B 页面B 页面报错帮我看看 A 页面传了什么参数过去。这种跨页面追踪靠人工翻日志几乎不可能但 AI 可以轻松做到。6.4 与构建工具联动更进一步可以把 MCP 服务端和构建工具的 dev server 打通。当 AI 发现某个 bug 时直接触发一次热更新把修复后的代码推送到页面然后再次读取日志验证。这就形成了一个发现-修复-验证的自动闭环。虽然目前还比较理想化但随着 MCP 生态成熟这种工作流会越来越常见。我个人在实际操作中的体会是这套方案最大的价值不是省了截图的时间而是改变了调试的思维方式。以前是人找问题现在是人和 AI 一起看数据找问题。AI 不会累、不会漏看、能同时对比几十条日志这是人做不到的。当然AI 也会误判所以最终的判断权还是在你手里。把它当成一个不知疲倦的助手而不是替代品心态就对了。最后分享一个小技巧在页面端加一个标记按钮点击后往日志里插入一条特殊标记。这样你在 AI 对话里可以说读取标记之后的所有日志就能精准定位到你操作之后产生的数据避免被历史日志干扰。这个小小的标记机制在实际调试中能省下大量筛选时间。
返回列表