Web远程调试介绍

引言:

在现代Web开发中,能够实时调试和监控应用程序已经成为了开发者日常工作的一部分。针对那些需求复杂、跨平台、并且必须随时保证高可用性的Web应用,一个高效、稳定的远程调试工具至关重要。在这篇文章里,我们将详细介绍CDP的概念以及其devtools的工作原理,同时介绍一个devtools的扩展chii并展示它是如何实现的。让我们从基本概念开始,逐步深入了解这一有用的工具。

一 、CDP介绍

Chrome DevTools Protocol(CDP)在调试网页和DevTools之间的交流过程中扮演了数据通信协议的角色。CDP定义了一套用于与Chrome的各种内部组件通信的底层命令和事件集合,这些组件包括但不限于:渲染、布局、JavaScript执行环境等。

具体到CDP的定位和作用:

  1. 定位:CDP位于DevTools前端与浏览器的后端(也就是渲染进程、网络栈等)之间,作为两者交互的桥梁。
  2. 作用
  • 命令执行:通过CDP,DevTools可以执行各种命令,比如检查和修改DOM元素、监控和修改CSS样式、调试JavaScript代码、启动/停止性能记录等。
  • 事件监听:CDP允许DevTools订阅内部事件,例如监听网络请求、DOM变化、JavaScript执行异常等事件。当这些事件发生时,它们将通过CDP传递给DevTools。
  • 信息获取:通过CDP,DevTools可以查询浏览器内部状态,例如获取当前页面加载状态、捕获页面截图、获取性能数据等。

操作过程基本上是:当您进行某项操作时,比如点击DevTools中的“Elements”面板来检查页面元素,DevTools会通过CDP向浏览器发送一个命令,请求DOM树信息。浏览器接收到这个命令后,通过渲染进程查询具体的DOM信息,并将结果返回给DevTools,DevTools前端再将这些信息可视化呈现给开发者。

交换数据时的底层传输机制可能是IPC(适用于本地调试)或WebSocket(适用于远程调试),但无论具体使用哪种传输方式,CDP充当的角色和其功能不变。简言之,CDP提供了一种标准化的方式,让开发者能够以编程方式与Chrome浏览器互动,从而使自动化测试、远程调试等复杂的任务成为可能。

哪如果我们想实际给浏览器发送一个DCP命令该如何实现呢?

const WebSocket = require('ws'); // npm install ws

// 替换为实际的WebSocket调试URL,通常可以通过访问'http://localhost:9222/json'来获取
const wsUrl = 'ws://localhost:9222/devtools/browser/{sessionId}';

const ws = new WebSocket(wsUrl);

ws.on('open', function open() {
  // 发送一个CDP命令
  ws.send(JSON.stringify({
    id: 1, // 消息ID,用于匹配响应
    method: 'Runtime.evaluate', // 要执行的CDP方法
    params: {
      expression: 'console.log("Hello from CDP!");'
    }
  }));
});

ws.on('message', function incoming(message) {
  console.log('Received: %s', message);
});

注意,实际应用中您需要先启动Chrome以便开启远程调试功能,通常可以通过以下方式来启动(以命令行为例):

chrome --remote-debugging-port=9222

CDP的交互模式有两类:

  • 本地模式:指打开一个页面,然后F12出现DevTools,两者的交互模式就是本地模式。本地模式下的通信实际上通常是通过IPC(进程间通信)来实现的
  • 远程模式:像我们上面的示例代码。devtools和调试页面不在一个机器上。在这种模式下,可以用WebSocket来连接到远程实例并发送CDP命令,从而远程控制Chrome的实例

那么在远程模式下,我们如何去打开展示一个devtools呢?

二、devtools-frontend

devtools-frontend 是 Chrome DevTools 的前端部分的源代码,它是用来与用户直接交互的图形界面,包括我们在使用 Chrome 浏览器开发者工具时看到的各种面板(如 Elements、Console、Network、Sources 等)。

如果你要参与 DevTools 前端的扩展开发或者了解其底层工作原理,你通常需要查看或者操作 devtools-frontend 代码库。这份代码库是开源的,可以在 Chromium 项目的代码库中找到。这样的开源性使得开发者可以深入学习 DevTools 的实现,甚至可以自定义 DevTools 的功能。

以下是与 devtools-frontend 相关的一些基本操作介绍:

  1. 查看源代码:你可以在 Chromium 的代码库中或者 Google 的 devtools-frontend 镜像库(如果有的话)中查看源代码。
  2. 运行 DevTools 前端:可以将 devtools-frontend 源代码下载到本地开发环境中,然后运行它。这通常需要配置一些环境变量,可能还需要安装一些依赖项。
  3. 修改和扩展:你可以在本地修改 devtools-frontend 的源代码,添加新的功能或者修改现有功能。这通常涉及到 JavaScript、HTML 和 CSS 的编写。
  4. 构建及部署:在完成代码修改后,你可以使用 Chromium 源代码中提供的构建系统来构建和测试你的更改。

devtools-frontend 是非常复杂的一套代码基础设施,它不仅包括用户界面,还有与后端(即浏览器引擎本身)的通讯逻辑。归功于 CDP,devtools-frontend 与浏览器的其他部分(例如渲染引擎、JavaScript V8 引擎等)保持不断的通信,这允许开发者实时监控和修改网页。

所以,我们可以自己部署一套devtools-frontend,我们先看本地模式的交互逻辑图:

image.png
本地模式

然后再看一下远程模式:

image.png
远程模式

对比我们可以看到:

在 Chrome DevTools 的体系中,后端充当了桥梁的角色,连接了正在调试的页面(也就是目标页面)和 DevTools 的客户端(用户界面)。

后端通常通过 WebSocket (ws) 协议与调试页面建立连接,使用 Chrome DevTools Protocol(CDP)来传送消息。而 DevTools 前端部分则通过一种叫做 IPC(Inter-Process Communication,即进程间通信)机制与后端(也就是浏览器的一部分)进行通信。

这里的过程可以大致描述如下:

目标页面与后端:

  • 当开发者打开 DevTools 时,浏览器创建一个 WebSocket 服务器,该服务器监听某端口(例如,ws://localhost:9222/devtools/page/{pageId})。
  • 目标页面通过该 WebSocket 连接与浏览器内部的 DevTools 后端通信。后端负责将 DevTools 发出的命令传送给页面,并将页面的信息回传给 DevTools。

前端与后端:

  • DevTools 前端与浏览器后端不是通过 WebSocket 直接通信的,它们是在同一进程内的不同线程或者是不同的进程中运行(依赖于操作系统及浏览器架构)。
  • DevTools 前端通过内置的 IPC 机制将命令发送给后端,后端将这些命令转发到目标页面,然后将目标页面的响应结果回传给前端。
  • 这个 IPC 通信是浏览器内部实现的,通常对开发者来说是不可见的。

用户交互流程:

  • 用户在 DevTools 中进行各种操作,如设置断点、刷新页面、查看元素等。
  • DevTools 前端产生相应的 CDP 命令,通过 IPC 发送给后端。
  • 后端通过 WebSocket 将这些命令转发给目标页面的 DevTools 代理。
  • 目标页面执行这些命令并返回结果。
  • 后端再将结果通过 IPC 送回前端,展示给用户。

这样的设计允许 DevTools 的前端和后端可以分离,甚至可以运行在不同的系统或者设备上,只要他们能够通过一些通讯协议(如 TCP/IP、WebSocket、IPC 等)交换 CDP 消息就可以了。

到这里为止我们发现远程调试的一个短板,就是需要chrome启动开debug端口,在这面向C端页面上是不可能的,你不能要求每个浏览器用户开启一个固定的端口。后来发现github有一个chii的项目,解决思路比较巧妙,下面我们一起来看一下。

三、Chii

Chii是一款web远程调试工具,其实现是对devtools-frontend的修改和扩展。它通过引入一层中介chobitsu,来解决我们上面所提到的需要浏览器开启debug端口的问题。chobitsu是CDP协议的JavaScript版本实现。其逻辑图如下:

image.png
chii逻辑架构图

它的使用非常的简单:

npm install chii -g
chii start -p 8080

在调试页面引入:

<script src="//host-machine-ip:8080/target.js" embedded="true"></script>

它本身分两种模式:

  • 远程模式:不带属性embedded="true"
  • 内嵌模式:带属性embedded="true",内嵌模式就是打开后直接显示内嵌devtools,效果如图:

chobitsu也是chii团队提炼出的一个子功能。构思很是巧妙,目前基本能涵盖多数场景,比如Dom结构,Storage信息,CSS,Network,但仍然有关键的部位无法实现(js本身无法模拟)。

四、chobitsu的实现原理分析

首先,JavaScript是无法直接和CDP接口进行交互的。下面以它的一个DOM.ts

chobitsu源码

我们看到了什么?没错,是mutationObserver。到这里我们基本就对chobitsu实现理解有了了解。它并不是真正的去和浏览器的CDP接口进行交互,而是一种模拟实现。

再看一个Overlay.ts,鼠标在devtools的dom节点上滑动,调试页面会跟随高亮显示P:

overlay高亮显示

也是模拟,监听鼠标move事件,然后通过LunaDomHighlighter组件,对划过的元素进行高亮显示。

从这两个例子我们大概就能理解,chobitsu会接收真实的CDP指令,然后进行模拟实现。所以就有一个问题,

像断点调试这种需要真正调用CDP接口的,它依然无法实现。虽然没有做到完美,但其实已经解决了90%的问题了,后续我们可以一起想想,有什么解决思路。

结语:

在本文中,我们一起探索了网页远程调试的概念,面对的挑战,以及可能的解决方案。但关键还是要把这些知识用于实战,解决实际中的问题。例如,借鉴Chii这类工具,我们可以构建一个在线的远程调试页面,这对于移动设备尤其有效,它让我们可以清晰地掌握到真实设备的运行情况。

此外,这项技术在低代码环境下同样可以发挥作用,成为其中的一个便捷调试工具。不过,除了技术本身,更让人觉得有价值的是它背后的创新思维。别人如何将旧技术变新应用,勇于尝试的态度,这是我们应该学习和思考的。技术永远在变,学会借鉴别人的创意和

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容