美文网首页
Web远程调试介绍

Web远程调试介绍

作者: cd2001cjm | 来源:发表于2024-02-19 10:11 被阅读0次

    引言:

    在现代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这类工具,我们可以构建一个在线的远程调试页面,这对于移动设备尤其有效,它让我们可以清晰地掌握到真实设备的运行情况。

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

    相关文章

      网友评论

          本文标题:Web远程调试介绍

          本文链接:https://www.haomeiwen.com/subject/wrqvadtx.html