隱藏在Web除錯背後的祕密

蘇格團隊發表於2019-04-22
  • 蘇格團隊
  • 作者:Jonny

一、除錯技術的起源

對於每位開發者而言,bug已經是不能再尋常的東西,debug也是家常便飯的事情。然而尋根溯源起來,還得從上個世紀五十年代講起。

1947年9月9日,哈佛大學在測試馬克II型艾肯中繼器計算機的時候,一隻飛蛾粘在一個繼電器上,導致計算機無法正常工作,操作員把飛蛾移除之後,計算機又恢復了正常運轉。於是他們將這隻飛蛾貼在了他們當時記錄的日誌上,並在日誌最後寫了這樣一句話:First actual case of bug being found。這是他們發現的第一個真正意義上的 bug,這也是人類計算機軟體歷史上發現的第一個 bug。他們也提出了一個詞,“debug(除錯)”了機器,由此引出了計算機除錯技術的發展。

隱藏在Web除錯背後的祕密

二、Chrome 開發者工具

對於web前端而言,我們每天都在使用開發除錯工具進行檢視dom結構、js斷點和檢視分析登入請求等操作,最熟悉的開發除錯工具 應該莫過於Chrome的Devtools和Firefox的FireBug了。

Chrome 開發者工具其實是一個用 HTML,JavaScript 和 CSS 寫的 Web 應用程式,被整合在瀏覽器中。其基於遠端除錯協議,與瀏覽器架構關係如下:

隱藏在Web除錯背後的祕密

由圖可知:

  • 遠端除錯協議基於 WebSocket,利用 WebSocket 建立連線 DevTools 和瀏覽器核心的快速資料通道
  • 瀏覽器擁有多個 Tab,併為每個 Tab 單獨提供 Websocket 的 Endpoint URI
  • 每個 DevTool 例項只能檢視一個 Tab,即只能與一個 Tab 保持通訊

事實上,Chrome開發者工具不僅只是可以在當前的瀏覽器頁面直接開啟,它作為一個客戶端(開源),也可以用來除錯任何支援遠端除錯協議的瀏覽器。

使用文件:developers.google.com/web/tools/c…

github倉庫:github.com/ChromeDevTo…

三、遠端除錯協議(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,否則兩方都無法正確的判斷請求和返回的匹配狀況。

隱藏在Web除錯背後的祕密
隱藏在Web除錯背後的祕密

  • notification:和第一種不同,這種模式用於由一方單方面的通知另一方某個資訊。和 “事件” 的概念類似。

隱藏在Web除錯背後的祕密

  1. Chrome的上層封裝: 為了更加方便Chrome extension的開發,Chrome偵錯程式擴充套件API提供了更高階別的API ——Chrome Debugger API。此API隱藏請求ID並處理請求與其響應的繫結,因此允許sendCommand在回撥函式呼叫中處理結果。每個 command 包含 request 和 response 兩部分,request 部分指定所要進行的操作以及操作說要的引數,response 部分表明操作狀態,成功或失敗。

以Debugger Domain為例,

  • command結構如下:

隱藏在Web除錯背後的祕密

  • 事件結構如下:

隱藏在Web除錯背後的祕密

協議文件:chromedevtools.github.io/devtools-pr…

Debugger API: developer.chrome.com/extensions/…

我們可以通過devtools來檢視Devtools Extension與瀏覽器核心實際通訊的資料情況,步驟如下:

1、開啟開發者工具實驗模式:

  • 瀏覽器進入chrome://flags
  • 找到Developer Tools Experiments
  • 狀態改為enable
  • 重啟瀏覽器

2、開啟協議監控tab

  • 點選devtools工具右上角選單圖示,進入“settings”,左邊選擇“Experiments”tab,將“Protocol Monitor”打上勾
  • 關閉devtools後重新開啟,點選devtools工具右上角選單圖示,再進入“More Tools”,選擇“Protocol monitor"

之後我們便可以看到:

隱藏在Web除錯背後的祕密

四、Chrome的遠端除錯模式:

從上面我們已經知道,Devtools是如何基於遠端除錯協議與瀏覽器核心進行互動的了,然而,不僅僅如此,Chrome還可以開啟遠端除錯模式,允許外部客戶端(支援遠端除錯協議)對其進行除錯。

  1. 協議Server端:

首先,以遠端除錯模式開啟Chrome:

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

之後除錯資料會轉發到本地9222埠,瀏覽器輸入localhost:9222/json可以看到:

隱藏在Web除錯背後的祕密

其中我們可以看到每個tab頁面對應的websocket url,通過該url建立連線便可以和系統核心進行通訊了。

  1. 協議客戶端:

我們可以採用Chrome內建的工具與其建立連線進行除錯,步驟如下:

1)開啟Chrome 內建客戶端,在瀏覽器輸入:

http://localhost:9222

可以看到以下介面:

隱藏在Web除錯背後的祕密

2)或者在chrome://inspect介面,我們可以發現,此時本地瀏覽器也可以被作為一個remote device來除錯了。

隱藏在Web除錯背後的祕密

3)我們也可以採用一個外部的除錯工具,如node程式,vscode外掛等,通過從9222埠獲取到各個頁面的json資料,然後進行websocket連線進行通訊,進行實現各種豐富的開發除錯功能。

五、移動端遠端除錯技術:

從上面看,chrome等瀏覽器的遠端除錯模式似乎有點雞肋,我都有Devtools工具了,何必還要多此一舉去開啟遠端除錯模式用其他工具來除錯。別急,遠端除錯模式真正發揮作用的還是移動端裝置的除錯場景。移動端裝置有執行環境,卻沒有合適的開發和除錯環境,藉助於webkit的遠端除錯模式,可以使得我們很方便的檢視和除錯移動端裝置。

移動端web遠端除錯技術很多種,像weinre等在程式碼中嵌入指令碼的就不說了,我們以基於webkit遠端除錯協議的方式來講解。 從上面我們已經知道,移動端chrome開啟遠端除錯模式後json資料會被打到debugging埠(localhost:9222),因為安全考慮,chrome限制了只能是本地localhost的,不能打到指定ip之上。此時,需要通過某種方式,將移動端9222埠的資料繫結到pc端,之後才能PC端便可以通過PC端本地埠與移動端頁面進行除錯。

隱藏在Web除錯背後的祕密

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 root@192.168.*.*

六、除錯伺服器指令碼(node程式):

2016年,Node將 Chrome瀏覽器的"開發者工具"作為官方的除錯工具,使得 Node 指令碼也可以使用圖形介面除錯,這大大方便了開發者。開啟除錯方式如下:

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

然後通過chrome://inspect可以看到app.js的除錯入口,開啟之後出現Devtools的定製版,只有四個Tab,移除了和伺服器指令碼除錯無關的部分。

隱藏在Web除錯背後的祕密

可以發現,node指令碼除錯的原理與chrome js指令碼相似,其內建V8支援遠端除錯協議,開啟除錯後作為一個server端,devtools客戶端通過websocket與其建立連線進行通訊。

六、總結

至此,我們已經介紹了本地除錯和遠端除錯已經隱藏在其背後的通訊原理。遠端除錯協議作為一個強大的通用的協議,支援了不同server或客戶端的通訊。

瀏覽器的除錯,其實最後都落腳到引擎:渲染引擎和 JavaScipt 引擎。對於css的修改、js的斷點等,如何落實到渲染引擎上,上下文環境切換,函式呼叫棧追蹤等等,還有更多東西值得挖掘。

相關文章