推广 热搜: page  小红  红书  数据  论文  考试  数据分析  关键词  哪些  搜索 

Chrome DevTools 远程调试协议分析及实战

   日期:2025-01-01     移动:https://sicmodule.kub2b.com/mobile/quote/17720.html

Chrome DevTools 可以说是前端开发最常用的工具,无论是普通页面、移动端 webview、小程序、甚至 node 应用,都可以用它来调试。

Chrome DevTools 提供的功能非常丰富,包含 DOM、debugger、网络、性能等许多能力。

为什么 Chrome DevTools 能够适用这么多场景?如何把 Chrome DevTools 移植到新的应用场景?Chrome DevTools 提供的功能我们能不能拆解出模块单独使用?今天我们来尝试探索这些问题。

Chrome DevTools 包括四个部分:

Chrome DevTools

我们可以看到,Chrome DevTools 的核心是调试器协议。

协议按域「Domain」划分能力,每个域下有 Method、Event 和 Types。

Method 对应 socket 通信的请求/响应模式,Events 对应 socket 通信的发布/订阅模式,Types 为交互中使用到的实体。

例如:

一个调试器后端,应当实现对 Method 的响应,并在适当的时候发布 Event。

一个调试器前端,应当使用 Method 请求需要的数据,订阅需要的 Event。

browser_protocol & js_protocol

协议分为 browser_protocol[4]js_protocol[5] 两种。

browser_protocol 是浏览器后端使用,js_protocol 是 node 后端使用。除此之外,还有对应的 Typescript 类型定义[6]

js_protocol 只有以下四个域「Console、Schema 已废弃」:

能力比 browser_protocol 少很多,这是因为页面有相对固定的工作模式,node 应用却千差万别。

browser_protocol 主要有以下几个域:

涉及了页面开发的方方面面。

devtools-frontend 即调试器前端,我们平常使用的调试面板,其源码可以从 ChromeDevTools/devtools-frontend[7] 获得。我们先来看一下它是怎么工作的。

项目结构

ChromeDevTools/devtools-frontend[8] 下载源码后,我们进入 front_end 目录,可以看到如下结构:

front_end 目录下的每一个 json 文件会有一个同名的 js 文件,有的还会有一个同名的 html 文件。

它们都代表一个应用,如 inspector.json 是其配置文件。如果此应用有界面,则带有 html,可以在浏览器中打开 html 运行应用。

我们可以看到熟悉的应用,inspector、node、devtools、ndb 等等。

devtools_app 即我们常用的调试面板,如图所示:

devtools

inspector 在 devtools_app 基础上增加了页面快照,可以实时看到页面的变化,并且可以在页面快照上交互,如图所示:

inspector

以 devtools_app 为例,我们来看配置文件的语义:

我们再来看一下模块,所有的模块都平级放在 front_end 目录下,不存在嵌套,每个模块都有一个 module.json 文件,表示此模块的配置。

之所以有这些配置,是因为,front_end 有自己的一套模块加载逻辑,和通常的 node 应用和前端应用都不一样。

初始化

front_end 各个应用初始化的过程类似,基本如下:

虽然 js 代码都是通过 import 来引用依赖,但是 front_end 并非使用 import 来加载模块,而是自己写了一个模块加载逻辑,先请求模块文件,然后在根据依赖关系把代码 eval。

作为调试器前端,socket 通信是不可或缺的,初始化的主要工作就是对调试器后端建立 socket 连接,准备好调试协议。

对于页面应用来说,还需要初始化 UI,front_end 未使用任何渲染框架,全部都是原生 DOM 操作。

远程调试

我们可以用 front_end 来实现远程调试页面,例如:用户在自己的 PC、APP 上操作页面,开发人员在另外一台电脑上观察页面、网络、控制台里发生的变化,甚至通过协议控制页面。

开启调试端口

不同后端打开调试端口的方式不同,以 chrome 为例:

chrome 和内嵌的调试面板使用 Embedder channel 通信,这个消息通道不能被用来做远程调试,远程调试我们需要使用 websocket channel。

使用 websocket channel 我们还需要打开 chrome 的远程调试端口,以命令行参数 remote-debugging-port 打开 chrome。

或者使用脚本 。

调试端口打开后,chrome 会启动一个内置的 http 服务,我们可以从中获取 chrome 的基本信息,其中最重要的是各个 tab 页的 websocket 通信地址。

chrome 提供的 http 接口如下,访问方式全部为 GET:

注意:这些接口都不能跨域,可以通过服务器访问,或者直接在浏览器中打开,但是不能使用 ajax 访问。

连接

获取到 webSocketDebuggerUrl 后,我们就可以用此连接来调试页面。front_end 下的 devtool、inspector 等应用均可使用。

观察 初始化 socket 链接的代码可以得知,我们需要把 webSocketDebuggerUrl 以 url 参数的形式传给应用,参数名为 ws。

我们在 front_end 目录下启动静态服务器。

然后访问 http://localhost:8002/inspector?ws=localhost:9222/devtools/page/8ED9DABCE2A6BD36952657AEBAA0DE02

我们可以看到页面上的一切变化都会出现在 inspector 的界面中。

跨域

如果前端和后端都在同一网段,我们使用以上方式就可以进行调试了,但是如果前后端在不同的内网内,我们如何实现远程调试?

只要我们有一台放在公网的服务器就可以调试。

前端和后端都在各自的内网内,因此相互之间肯定无法直接访问。但是它们都可以访问公网的服务器,并且,websocket 是可以跨域的。

因此我们可以通过两次转发,让不同内网的前端和后端交互,具体步骤如下:

注意:因为 json/list 是 http 接口,无法跨域,这一步必须手动获取,然后把 webSocketDebuggerUrl 放在 url 参数上传给 launcher.js

手动获取 webSocketDebuggerUrl

这样,我们的 socket 链路上有了四个节点,分别是:

server 和 laucher 完全作为转发器,转发两边传来的信息,即可实现 front_end 到 debugger 的交互。

注意:如果 front_end 请求了 Network.enable, 就不能把 laucher.js 所在的页面作为调试页面,因为 laucher.js 收到 debugger 传来的数据会触发 Network.webSocketframeReceived 推送,这个推送本身又会触发 Network.webSocketframeReceived ,造成无限循环。处理方式有两种,一是拦截掉 Network.enable 请求,这样会取消掉所有的 Network 的推送。二是不把 laucher.js 所在的页面作为调试页面,仅作数据中转用。

远程调试

websocket 服务代码示例:

laucher.js 代码示例:

回放

使用 inspector 时我们可以发现,只要开启了 Page.enable 和 Network.enable,就可以一直接收到调试器后端推送的页面快照和网络请求数据。

我们可以略微改造一下 server.js 的代码,把所有收到的推送数据打时间戳后保存到一个文件,持久化存储起来。

然后我们给 websocket 服务增加一个协议类型,和 inspector 建立连接后,读取文件中保存的数据,按照时间戳上的时间间隔推送数据。

这样就实现了回放功能,把之前调试时的现场重现一遍。

甚至可以更进一步,创建一个 websocket 服务作为调试器前端,模拟 inspector 发送请求的逻辑并保存推送数据到文件,这样就实现了一个录制服务器,可以随时录制调试现场,然后在需要的时候播放,因为记录了时间戳,pause、seek、resume、stop 都可以实现。

devtools-frontend 的调用方式

一般来说,我们习惯用 require/import 的方式调用模块,devtools-frontend 虽然也是个 npm 包 ,chrome-devtools-frontend[9],但是却不方便用 require/import 的方式直接引用。

主要是因为之前所述的 front_end 应用有自己的一套模块加载逻辑,应用的 js、json 配置文件必须在同一个目录下,模块也必须在同一个目录下,否则就会出现路径错误。

如果仅使用 front_end 的某个模块,还可以用 require/import 来引用。

如果想创建一个新的应用,最好是把整个 front_end 复制过来修改。

如果想在 chrome 内嵌的调试面板中增加自定义的能力,可以用 chrome 插件的方式实现,例如vue-devtools[10]

ChromeDevTools/awesome-chrome-devtools[11]

ChromeDevTools/devtools-protocol[12]

参考资料

[1]

devtools-protocol: https://github.com/chromedevtools/devtools-protocol

[2]

Puppeteer: https://github.com/GoogleChrome/puppeteer/

[3]

ndb: https://github.com/GoogleChromeLabs/ndb

[4]

browser_protocol: https://github.com/ChromeDevTools/devtools-protocol/blob/master/json/browser_protocol.json

[5]

js_protocol: https://github.com/ChromeDevTools/devtools-protocol/blob/master/json/js_protocol.json

[6]

Typescript 类型定义: https://github.com/ChromeDevTools/devtools-protocol/tree/master/types

[7]

ChromeDevTools/devtools-frontend: https://github.com/ChromeDevTools/devtools-frontend

[8]

ChromeDevTools/devtools-frontend: https://github.com/ChromeDevTools/devtools-frontend

[9]

chrome-devtools-frontend: https://www.npmjs.com/package/chrome-devtools-frontend

[10]

vue-devtools: https://github.com/vuejs/vue-devtools

[11]

ChromeDevTools/awesome-chrome-devtools: https://github.com/ChromeDevTools/awesome-chrome-devtools

[12]

本文地址:https://sicmodule.kub2b.com/quote/17720.html     企库往 https://sicmodule.kub2b.com/ , 查看更多

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


0相关评论
相关最新动态
推荐最新动态
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号