CDP 遠端除錯方案
什麼是 cdp 協議
cdp 協議簡稱 chrome 除錯協議,是基於 scoket(websocket、usb、adb )訊息的 json rpc 協議。用來呼叫 chrome 內部的方法實現 js,css ,dom 的開發除錯。 可以將 實現了 cdp 協議的應用 看做 rpc 呼叫的服務端( chrome ,puppeteer), 將除錯面板看做 rpc 呼叫的客戶端(devtools)。
devtools 除錯系統
完整的除錯系統分別由前端,後端,協議,通道四部分組成
- Frontend: 偵錯程式前端,如 chrome-devtools-frontend 一個 web 應用,接收 cdp 事件&傳送 cdp 命令,實現 dom,network,debugger 的執行除錯。
- Backend : 實現了 cdp 協議的應用,會接收 cdp 命令&傳送 cdp 事件。Chromium、V8 或 Node.js
- Protocol: cdp 除錯協議,偵錯程式前端和後端使用此協議通訊。 它分為代表被檢查實體的語義方面的域。 每個域定義型別、命令(從前端傳送到後端的訊息)和事件(從後端傳送到前端的訊息)。該協議基於 json rpc 2.0 執行;
- Channels: 訊息通道,後端和前端之間傳送協議訊息的一種方式。包括:Embedder Channel、WebSocket Channel、Chrome Extensions Channel、USB/ADB Channel。
chrome 遠端除錯
如上,所有能夠消費傳送 cdp 訊息的應用都可以被 chrome-devtools-frontend 除錯。chrome 集成了cdp協議,所以只需要通過訊息通道與 chrome-devtools-frontend 應用 建立 socket 連結就可以被除錯端除錯。除錯啟動分為三步:
- 啟動 cdp 服務端
- 啟動 cdp 客戶端
- 建立連結
啟動 cdp 服務端
以 Chrome,puppetter 為例啟動 backend 應用,設定除錯埠 9222。
- chrome
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=./test
- puppetter
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ args: ['--remote-debugging-port=9222', '--remote-debugging-address=0.0.0.0'], }); const page = await browser.newPage(); // let res= await page.goto('http://www.baidu.com'); console.log(browser.wsEndpoint()); // output -> ws://127.0.0.1:57724/devtools/browser/705082a5-19e6-4e9a-b8a6-477b7b6e1bd6 })();
此時訪問 http://0.0.0.0:9222/json 此時可以獲取除錯頁面 id 和 頁面的 webSocketDebuggerUrl ,代表 backend 端啟動成功。
[ { "description": "", "devtoolsFrontendUrl": "/devtools/inspector.html?ws=0.0.0.0:9222/devtools/page/659E9C174913FC5670B5F6E78B6B91FD", "id": "659E9C174913FC5670B5F6E78B6B91FD", "title": "歡迎使用 Chrome", "type": "page", "url": "chrome://welcome/", "webSocketDebuggerUrl": "ws://0.0.0.0:9222/devtools/page/659E9C174913FC5670B5F6E78B6B91FD" }, { "description": "", "devtoolsFrontendUrl": "/devtools/inspector.html?ws=0.0.0.0:9222/devtools/page/9902C5D5F55923DFC457B7AA423F957E", "faviconUrl": "http://cn.bing.com/sa/simg/favicon-2x.ico", "id": "9902C5D5F55923DFC457B7AA423F957E", "title": "必應", "type": "page", "url": "http://cn.bing.com/", "webSocketDebuggerUrl": "ws://0.0.0.0:9222/devtools/page/9902C5D5F55923DFC457B7AA423F957E" }, { "description": "", "devtoolsFrontendUrl": "/devtools/inspector.html?ws=0.0.0.0:9222/devtools/page/428C9AC3F9B6AF7235CC41D849DD7589", "faviconUrl": "http://www.baidu.com/favicon.ico", "id": "428C9AC3F9B6AF7235CC41D849DD7589", "title": "百度一下,你就知道", "type": "page", "url": "http://www.baidu.com/", "webSocketDebuggerUrl": "ws://0.0.0.0:9222/devtools/page/428C9AC3F9B6AF7235CC41D849DD7589" } ]
啟動 cdp 客戶端
chrome-devtools-frontend 作為一個純 web 應用,可以通過 koa 部署訪問。同時 chrome 預設也集成了 chrome-devtools-frontend 服務。在 cdp 服務端啟動後可以直接訪問 http://0.0.0.0:9222/devtools/inspector.html 。
建立連結
傳入 socket_backend_url , http://0.0.0.0:9222/devtools/inspector.html?ws= ${webSocketDebuggerUrl}
或者直接訪問 [http://0.0.0.0:9222/](http://0.0.0.0:9222/devtools/inspector.html?ws=0.0.0.0:9222/devtools/page/9902C5D5F55923DFC457B7AA423F957E) 可以看到瀏覽器中的的tab執行緒頁,點選需要除錯的頁面,[http://0.0.0.0:9222/devtools/inspector.html?ws=0.0.0.0:9222/devtools/page/9902C5D5F55923DFC457B7AA423F957E](http://0.0.0.0:9222/devtools/inspector.html?ws=0.0.0.0:9222/devtools/page/9902C5D5F55923DFC457B7AA423F957E) , 就可以連線 [chrome-devtools-frontend](http://github.com/ChromeDevTools/devtools-frontend) 除錯了。
此時開啟 network,檢視 ws ,可以看到 backend 端在接收 chrome-devtools-frontend 傳送的 cdp 命令,並將 dom,network,資源資訊返回給遠端除錯端
cdp協議結構
cdp 協議按域「Domain」劃分能力,每個域下有 Method、Event 和 Types。([http://chromedevtools.github.io/devtools-protocol/tot/Debugger/](http://chromedevtools.github.io/devtools-protocol/tot/Debugger/) )
Method 對應 socket 通訊的請求/響應模式,Events 對應 socket 通訊的釋出/訂閱模式,Types 為互動中使用到的實體。
用遠端執行一段 js 為例,在 chrome-devtools-frontend 控制檯輸入下面程式碼,backend 端分別收到執行三個 cdp 命令。 Runtime.compileScript->Runtime.evaluate->Runtime.compileScript
pp=function(){ alert(244) } pp()
{ "id": 47, "method": "Runtime.evaluate", "params": { "expression": "pp=function(){alert(244)}", "includeCommandLineAPI": true, "generatePreview": true, "userGesture": false, "awaitPromise": false, "throwOnSideEffect": true, "timeout": 500, "disableBreaks": true, "replMode": true, "uniqueContextId": "-3083772769491583108.6833303176535544523" } }
{ "id": 178, "method": "Runtime.compileScript", "params": { "expression": "pp=function(){alert(244)}", "sourceURL": "", "persistScript": false, "executionContextId": 7 } }
{ "id": 100, "method": "Runtime.compileScript", "params": { "expression": "pp()", "sourceURL": "", "persistScript": false, "executionContextId": 7 } }
手動實現
H5 端通過 CDP 協議呼叫除錯
var ws = new WebSocket('ws://127.0.0.1:9222/devtools/page/620F91C22D41B614947001C52AC55E53'); window.ppp=function(){ // 呼叫 Command debugger ws.onmessage = function(event) { console.log(event.data); // 獲取資料:{"method": "Page.loadEventFired", "params": {"timestamp": 1402317772.874949}} }; ws.send('{"id": 1, "method": "Page.navigate", "params": {"url": "http://www.github.com"}}'); }
遠端除錯
chrome 社群提供了基礎的遠端除錯方案 : devtools-remote 。 分別提供 websocket 服務做訊息轉發 和 chrome 外掛在 backend 端來監聽執行傳送 cdp 訊息。
devtools-remote 除錯外掛在 background 層實現 cdp 訊息監聽, 響應和執行。主要依賴下面幾個 api 。 Chrome Extensions Api( chrome.debugger )
- chrome.debugger.getTargets : 獲取可除錯目標的列表( tab_id )
- chrome.debugger.attach : 將偵錯程式附加到指定目標。
- chrome.debugger.sendCommand: 將 cdp 命令傳送至除錯目標。
- chrome.debugger.onEvent.addListene : 監聽指定選項卡頁中的所有事件,在回撥函式 response cdp 訊息到 scocket 服務端。
外掛內部邏輯實現
- 點選外掛(chrome.browserAction.onClicked.addListener)獲取當前頁 tabID ,即目標 id.
- 呼叫 chrome.debugger.attach,將偵錯程式附加到指定目標。
- socket connect 連線代理 websocket 伺服器。(代理伺服器連線除錯應用 chrome-devtools-frontend )
- 外掛連線成功: 監聽從代理伺服器推送的 data.request 型別訊息。 呼叫 chrome.debugger.sendCommand 執行 cdp 協議的命令, 將執行結果返回給socket服務端訊息事件名為 data.response 訊息 id 保持一致)。
- 呼叫 chrome.debugger.onEvent.addListener,監聽除錯頁的所有事件,轉成 cdp 的訊息結構 {method: method, params: params} ,傳送訊息事件名為 data.event 到代理伺服器,最終轉發到除錯應用
socket_proxy 邏輯代理伺服器的邏輯很簡單,將來自外掛端 'data.response' , 'data.event' 的事件訊息轉發到除錯應用上。 將來自除錯應用 'data.request' 事件訊息轉發到 backend 外掛端。
此外社群還有 chobitsu 這樣的 cdp 解析庫,提供了 Storage、Runtime、Network、DOM、DOMDebugger、DOMStorage 的能力。與需要依賴在外掛 background 層執行 chrome.debugger API 的方案不同。chobitsu 在瀏覽器執行時環境中手動實現了cdp 協議。 基於chobitsu 的能力可以實現待除錯頁面通過載入 backend.js 監聽瀏覽器事件 執行 cdp 命令,實現 dom css network 的遠端除錯。 具體用例可以參考 devtools-pro 。由此方案進一步聯想到xss安全的重要性。
同理 react-devtools 的實現方案,也與cdp方案 類似, 在除錯頁面中引入 或者 通過外掛插入 backend.js,監聽變化傳送到除錯應用。
參考文件
❉ 作者介紹 ❉
- 淺談低程式碼平臺遠端元件載入方案
- 前端富文字基礎及實現
- 淺談前端埋點&監控
- 如何讓 x == 1 && x == 2 && x == 3 等式成立
- 淺析 path 常用工具函式原始碼
- web components-LitElement實踐
- 模組聯邦淺析
- 效能優化——圖片壓縮、載入和格式選擇
- 如何基於 WebComponents 封裝 UI 元件庫
- CDP 遠端除錯方案
- 如何落地一個智慧機器人
- Form 資料形式配置化設計
- Lerna 執行流程剖析
- Decorator 裝飾器
- 淺析snabbdom中vnode和diff演算法
- 函數語言程式設計(FP)
- 如何利用 SCSS 實現一鍵換膚
- 淺析FormData
- Flutter For Web 編譯的兩種方案
- Web 多執行緒開發利器 Comlink 的剖析與思考