Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web调试技术详解 #26

Open
SugarTeam opened this issue Jun 16, 2020 · 0 comments
Open

Web调试技术详解 #26

SugarTeam opened this issue Jun 16, 2020 · 0 comments
Labels

Comments

@SugarTeam
Copy link
Contributor

一、调试技术的起源

对于每位开发者而言,bug已经是不能再寻常的东西,debug也是家常便饭的事情。然而寻根溯源起来,还得从上个世纪五十年代讲起。

1947年9月9日,哈佛大学在测试马克II型艾肯中继器计算机的时候,一只飞蛾粘在一个继电器上,导致计算机无法正常工作,操作员把飞蛾移除之后,计算机又恢复了正常运转。于是他们将这只飞蛾贴在了他们当时记录的日志上,并在日志最后写了这样一句话:First actual case of bug being found。这是他们发现的第一个真正意义上的 bug,这也是人类计算机软件历史上发现的第一个 bug。他们也提出了一个词,“debug(调试)”了机器,由此引出了计算机调试技术的发展。

二、Chrome 开发者工具

对于web前端而言,我们每天都在使用开发调试工具进行查看dom结构、js断点和查看分析登录请求等操作,最熟悉的开发调试工具 应该莫过于Chrome的Devtools和Firefox的FireBug了。

Chrome 开发者工具其实是一个用 HTML,JavaScript 和 CSS 写的 Web 应用程序,被集成在浏览器中。其基于远程调试协议,与浏览器架构关系如下:

由图可知:

  • 远程调试协议基于 WebSocket,利用 WebSocket 建立连接 DevTools 和浏览器内核的快速数据通道
  • 浏览器拥有多个 Tab,并为每个 Tab 单独提供 Websocket 的 Endpoint URI
  • 每个 DevTool 实例只能检视一个 Tab,即只能与一个 Tab 保持通讯

事实上,Chrome开发者工具不仅只是可以在当前的浏览器页面直接打开,它作为一个客户端(开源),也可以用来调试任何支持远程调试协议的浏览器。

使用文档:https://developers.google.com/web/tools/chrome-devtools/

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

三、远程调试协议(remote debugging protocol)

远程调试协议Webkit 在 2012 年就已经引入,目前所有 Webkit 内核的浏览器都支持这一特性。远程调试协议基于 WebSocket,利用 WebSocket 建立连接 客户端(如DevTools) 和浏览器内核的快速数据通道,Chrome的Devtools仅仅只是Webkit远程调试协议的一个应用案例。

  1. 通讯模式和消息结构:
    对于每个页面的所有操作,远程调试协议将其划分成了不同的命令域,如Browser、Dom、Debugger和Network等等,每个域定义了不同的命令和事件。在开发调试过程中,浏览器内核和远程客户端通过WebSocket发送消息进行通信,消息基本上分两种格式,一种是含有 message id 的,另一种是不含 message id 的,分别代表俩种通讯模式:
  • request/response:就如同一个异步调用,通过请求的信息,获取相应的返回结果。这样的通讯必然有一个 message id,否则两方都无法正确的判断请求和返回的匹配状况。


  • notification:和第一种不同,这种模式用于由一方单方面的通知另一方某个信息。和 “事件” 的概念类似。

  1. Chrome的上层封装:
    为了更加方便Chrome extension的开发,Chrome调试器扩展API提供了更高级别的API ——Chrome Debugger API。此API隐藏请求ID并处理请求与其响应的绑定,因此允许sendCommand在回调函数调用中处理结果。每个 command 包含 request 和 response 两部分,request 部分指定所要进行的操作以及操作说要的参数,response 部分表明操作状态,成功或失败。

以Debugger Domain为例,

  • command结构如下:

  • 事件结构如下:

协议文档:https://chromedevtools.github.io/devtools-protocol/tot/Browser

Debugger API: https://developer.chrome.com/extensions/debugger

我们可以通过devtools来查看Devtools Extension与浏览器内核实际通信的数据情况,步骤如下:

1、开启开发者工具实验模式:

  • 浏览器进入chrome://flags
  • 找到Developer Tools Experiments
  • 状态改为enable
  • 重启浏览器

2、打开协议监控tab

  • 点击devtools工具右上角菜单图标,进入“settings”,左边选择“Experiments”tab,将“Protocol Monitor”打上勾
  • 关闭devtools后重新打开,点击devtools工具右上角菜单图标,再进入“More Tools”,选择“Protocol monitor"

之后我们便可以看到:

四、Chrome的远程调试模式:

从上面我们已经知道,Devtools是如何基于远程调试协议与浏览器内核进行交互的了,然而,不仅仅如此,Chrome还可以开启远程调试模式,允许外部客户端(支持远程调试协议)对其进行调试。

  1. 协议Server端:

首先,以远程调试模式打开Chrome:

./chrome --remote-debugging-port=9222

之后调试数据会转发到本地9222端口,浏览器输入localhost:9222/json可以看到:

其中我们可以看到每个tab页面对应的websocket url,通过该url建立连接便可以和系统内核进行通信了。

  1. 协议客户端:

我们可以采用Chrome内置的工具与其建立连接进行调试,步骤如下:

1)打开Chrome 内置客户端,在浏览器输入:

http://localhost:9222

可以看到以下界面:

2)或者在chrome://inspect界面,我们可以发现,此时本地浏览器也可以被作为一个remote device来调试了。

3)我们也可以采用一个外部的调试工具,如node程序,vscode插件等,通过从9222端口获取到各个页面的json数据,然后进行websocket连接进行通信,进行实现各种丰富的开发调试功能。

五、移动端远程调试技术:

从上面看,chrome等浏览器的远程调试模式似乎有点鸡肋,我都有Devtools工具了,何必还要多此一举去开启远程调试模式用其他工具来调试。别急,远程调试模式真正发挥作用的还是移动端设备的调试场景。移动端设备有运行环境,却没有合适的开发和调试环境,借助于webkit的远程调试模式,可以使得我们很方便的查看和调试移动端设备。

移动端web远程调试技术很多种,像weinre等在代码中嵌入脚本的就不说了,我们以基于webkit远程调试协议的方式来讲解。
从上面我们已经知道,移动端chrome开启远程调试模式后json数据会被打到debugging端口(localhost:9222),因为安全考虑,chrome限制了只能是本地localhost的,不能打到指定ip之上。此时,需要通过某种方式,将移动端9222端口的数据绑定到pc端,之后才能PC端便可以通过PC端本地端口与移动端页面进行调试。

1、端口绑定方式:

  • 有线(USB线):以webkit为内核的移动端浏览器,开启浏览器远程调试功能之后通过usb连接到pc端,之后通过adb进行端口绑定:

adb forward tcp:9222 localabstract:chrome_devtools_remote

  • 无线(network):通过ssh 进行端口转发,本方式适合移动端支持ssh连接登录。

#在本地主机A1登陆远程云主机B1,并进行本地端口转发。2000端口绑定本地所有网卡 ssh -L 2000:localhost:3000 [email protected].*.*

六、调试服务器脚本(node程序):

2016年,Node将 Chrome浏览器的"开发者工具"作为官方的调试工具,使得 Node 脚本也可以使用图形界面调试,这大大方便了开发者。开启调试方式如下:

node --inspect --debug-brk index.js

然后通过chrome://inspect可以看到app.js的调试入口,打开之后出现Devtools的定制版,只有四个Tab,移除了和服务器脚本调试无关的部分。

可以发现,node脚本调试的原理与chrome js脚本相似,其内置V8支持远程调试协议,开启调试后作为一个server端,devtools客户端通过websocket与其建立连接进行通信。

六、总结

至此,我们已经介绍了本地调试和远程调试已经隐藏在其背后的通讯原理。远程调试协议作为一个强大的通用的协议,支持了不同server或客户端的通信。

浏览器的调试,其实最后都落脚到引擎:渲染引擎和 JavaScipt 引擎。对于css的修改、js的断点等,如何落实到渲染引擎上,上下文环境切换,函数调用栈追踪等等,还有更多东西值得挖掘。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant