调试技术的起源
1947 年 9 月 9 日,一名美国的科学家格蕾丝.霍普和她的同伴在对 Mark II 计算机进行研究的时候发现,一只飞蛾粘在一个继电器上,导致计算机无法正常工作,当他们把飞蛾移除之后,计算机又恢复了正常运转。于是他们将这只飞蛾贴在了他们当时记录的日志上,对这件事情进行了详细的记录,并在日志最后写了这样一句话:First actual case of bug being found。这是他们发现的第一个真正意义上的 bug,这也是人类计算机软件历史上,发现的第一个 bug,而他们找到飞蛾的方法和过程,就是 debugging 调试技术。
从格蕾丝调试第一个 bug 到现在,69 年的时间里,在计算机领域,硬件、软件各种调试技术都在不断的发展和演进。那么对于日新月异的前端来说,调试技术也尤其显得重要。淘宝前端团队也正在使用一些创新的技术和手段来解决无线页面调试的问题。今天先跟大家分享下浏览器远程调试技术,本文将用 Chrome/Webview 来作为案例。
调试原理
调试方式与权限管理
目前常规浏览器调试目标分为两种:Chrome PC 浏览器和 Chrome Mobile(Android 4.4 以后,Android WebView 其实就是 Chromium WebView)。
Chrome PC 浏览器
对于调试 Chrome PC 浏览器,可能大家经常使用的是用鼠标右键或者快捷方式(mac:option + command + J),唤起 Chrome 的控制台,来对当前页面进行调试。其实还有另外一种方法,就是使用一个 Chrome 浏览器调试另一个 Chrome 浏览器。Chrome 启动的时候,默认是关闭了调试端口的,如果要对一个目标 Chrome PC 浏览器进行调试,那么启动的时候,可以通过传递参数来开启 Chrome 的调试开关:
1 2 |
# for mac sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 |
Chrome Android 浏览器
对于调试 Android 上的 Chrome 或者 WebView 需要连接 USB 线。打开调试端口的方法如下:
1 |
adb forward tcp:9222 localabstract:chrome_devtools_remote |
跟 Chrome PC 浏览器不同的是,对于 Chrome Android 浏览器,由于数据传输是通过 USB 线而不是 WIFI,实际上 Chrome Android 创建的一个 chrome_devtools_remote 这个 path 的 domain socket。所以,上面一条命令则是通过 Android 的 adb 将 PC 的端口 9222 通过 USB 线与 chrome_devtools_remote 这个 domain socket 建立了一个端口映射。
权限管理
Google 为了限制调试端口的接入范围,对于 Chrome PC 浏览器,调试端口只接受来自 127.0.0.1
或者 localhost
的数据请求,所以,你无法通过你的本地机器 IP 来调试 Chrome。对于 Android Chrome/WebView,调试端口只接受来自于 shell
这个用户数据请求,也就是说只能通过 USB 进行调试,而不能通过 WIFI。
开始调试
通过以上的调试方式的接入以及调试端口的打开,这个时候在浏览器中输入:
1 |
http://127.0.0.1:9222/json |
将会看到类似下面的内容:
1 2 3 4 5 6 7 8 9 10 11 |
[ { "description": "", "devtoolsFrontendUrl": "/devtools/inspector.html?ws=127.0.0.1:9222/devtools/page/ebdace60-d482-4340-b622-a6198e7aad6e", "id": "ebdace60-d482-4340-b622-a6198e7aad6e", "title": "揭秘浏览器远程调试技术.mdown—/Users/harlen/Documents", "type": "page", "url": "http://127.0.0.1:51004/view/61", "webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/ebdace60-d482-4340-b622-a6198e7aad6e" } ] |
其中,最重要的 2 个参数分别是 id 和 webSocketDebuggerUrl。Chrome 会为每个页面分配一个唯一的 id,作为该页面的唯一标识符。几乎对目标浏览器的所有操作都是需要带上这个 id。
Chrome 提供了以下这些 http 接口控制目标浏览器
1 2 3 4 5 6 7 8 9 10 11 |
# 获取当前所有可调式页面信息 http://127.0.0.1:9222/json # 获取调试目标 WebView/blink 的版本号 http://127.0.0.1:9222/json/version # 创建新的 tab,并加载 url http://127.0.0.1:9222/json/new?url # 关闭 id 对应的 tab http://127.0.0.1:9222/json/close/id |
webSocketDebuggerUrl 则在调试该页面需要用到的一个 WebSocket 连接。chrome 的 devtool 的所有调试功能,都是基于 Remote Debugging Protocol 使用 WebSocket 来进行数据传输的。那么这个 WebSocket,就是上面我们从 http://127.0.0.1:9222/json
获取的 webSocketDebuggerUrl
,每一个页面都有自己不同的 webSocketDebuggerUrl
。这个 webSocketDebuggerUrl
是通过 url 的 query 参数传递给 chrome devtool 的。
chrome 的 devtool 可以从 Chrome 浏览器中进行提取 devtool 源码或者从 blink 源码中获取。在部署好自己的 chrome devtool 代码之后,下面既可以开始对 Chrome 进行调试, 浏览器输入一下内容:
1 |
http://path_to_your_devtool/devtool.html?ws=127.0.0.1:9222/devtools/page/ebdace60-d482-4340-b622-a6198e7aad6e |
其中 ws 这个参数的值就是上面出现的 webSocketDebuggerUrl。Chrome 的 devtool 会使用这个 url 创建 WebSocket 对该页面进行调试。
如何实现 JavaScript 调试
在进入 Chrome 的 devtool 之后,我们可以调出控制台,来查看 devtool 的 WebSocket 数据。这个里面有很多数据,我这里只讲跟 JavaScript 调试相关的。
图中,对于 JavaScript 调试,有一条非常重要的消息,我蓝色选中的那条消息:
1 |
{"id":6,"method":"Debugger.enable"} |
然后选中要调试的 JavaScript 文件,然后设置一个断点,我们再来看看 WebSocket 消息:
devtool 像目标 Chrome 发送了 2 条消息
1 2 3 4 5 6 7 |
Η机进行研究的时候发现,一只飞蛾粘在一个继电器上,导致计算机无法正常工作,当他们把飞蛾移除之后,计算机又恢复了正常运转。于是他们将这只飞蛾贴在了他们当时记录的日志上,对这件事情进行了详细的记录,并在日志最后写了这样一句话:First actual case of bug being found。这是他们发现的第一个真正意义上的 bug,这也是人类计算机软件历史上,发现的第一个 bug,而他们找到飞蛾的方法和过程,就是 debugging 调试技术。
从格蕾丝调试第一个 bug 到现在,69 年的时间里,在计算机领域,硬件、软件各种调试技术都在不断的发展和演进。那么对于日新月异的前端来说,调试技术也尤其显得重要。淘宝前端团队也正在使用一些创新的技术和手段来解决无线页面调试的问题。今天先跟大家分享下浏览器远程调试技术,本文将用 Chrome/Webview 来作为案例。 调试原理调试方式与权限管理目前常规浏览器调试目标分为两种:Chrome PC 浏览器和 Chrome Mobile(Android 4.4 以后,Android WebView 其实就是 Chromium WebView)。 Chrome PC 浏览器对于调试 Chrome PC 浏览器,可能大家经常使用的是用鼠标右键或者快捷方式(mac:option + command + J),唤起 Chrome 的控制台,来对当前页面进行调试。其实还有另外一种方法,就是使用一个 Chrome 浏览器调试另一个 Chrome 浏览器。Chrome 启动的时候,默认是关闭了调试端口的,如果要对一个目标 Chrome PC 浏览器进行调试,那么启动的时候,可以通过传递参数来开启 Chrome 的调试开关:
Chrome Android 浏览器对于调试 Android 上的 Chrome 或者 WebView 需要连接 USB 线。打开调试端口的方法如下:
跟 Chrome PC 浏览器不同的是,对于 Chrome Android 浏览器,由于数据传输是通过 USB 线而不是 WIFI,实际上 Chrome Android 创建的一个 chrome_devtools_remote 这个 path 的 domain socket。所以,上面一条命令则是通过 Android 的 adb 将 PC 的端口 9222 通过 USB 线与 chrome_devtools_remote 这个 domain socket 建立了一个端口映射。 权限管理Google 为了限制调试端口的接入范围,对于 Chrome PC 浏览器,调试端口只接受来自 开始调试通过以上的调试方式的接入以及调试端口的打开,这个时候在浏览器中输入:
将会看到类似下面的内容:
其中,最重要的 2 个参数分别是 id 和 webSocketDebuggerUrl。Chrome 会为每个页面分配一个唯一的 id,作为该页面的唯一标识符。几乎对目标浏览器的所有操作都是需要带上这个 id。 Chrome 提供了以下这些 http 接口控制目标浏览器
webSocketDebuggerUrl 则在调试该页面需要用到的一个 WebSocket 连接。chrome 的 devtool 的所有调试功能,都是基于 Remote Debugging Protocol 使用 WebSocket 来进行数据传输的。那么这个 WebSocket,就是上面我们从 chrome 的 devtool 可以从 Chrome 浏览器中进行提取 devtool 源码或者从 blink 源码中获取。在部署好自己的 chrome devtool 代码之后,下面既可以开始对 Chrome 进行调试, 浏览器输入一下内容:
其中 ws 这个参数的值就是上面出现的 webSocketDebuggerUrl。Chrome 的 devtool 会使用这个 url 创建 WebSocket 对该页面进行调试。 如何实现 JavaScript 调试在进入 Chrome 的 devtool 之后,我们可以调出控制台,来查看 devtool 的 WebSocket 数据。这个里面有很多数据,我这里只讲跟 JavaScript 调试相关的。 图中,对于 JavaScript 调试,有一条非常重要的消息,我蓝色选中的那条消息:
然后选中要调试的 JavaScript 文件,然后设置一个断点,我们再来看看 WebSocket 消息: devtool 像目标 Chrome 发送了 2 条消息 |