黃聰:如何擴展Chrome DevTools來獲取頁面請求

1. Chrome DevTools Extension

熟悉React的同窗,可能對React Developer Tools並不陌生,
javascript

 
 

 

剛看到的時候,我也以爲很神奇,
由於React Developer Tools和其餘Chrome Extension不一樣,
它竟然出如今了Chrome開發者工具欄中,和原生的DevTools同樣強大。
例如,能夠審查元素,查看元素的屬性,等等。css

後來才知道,像這種出如今Chrome開發者工具欄中的擴展,稱爲Chrome DevTools Extensionhtml

比起普通的Chrome Extension,Chrome DevTools Extension能夠訪問更多API,例如,
(1)devtools.inspectedWindow
(2)devtools.network
(3)devtools.panels
其中包括了,與當前審查窗口相關的,與網絡請求相關的,以及與開發者工具欄相關的API。java

2. 背景 & 基本概念

 
 

在某一具體項目中,有一個這樣的需求,
咱們須要選擇頁面中發起的http請求,而後將它們保存到數據庫中。react

因爲頁面發起的請求可能會發往不一樣的服務器,因此在服務器端解決這個問題就顯得比較麻煩,
而編寫一個Chrome DevTools Extension會更簡單直接。git

下文我將這個功能的核心抽離出來,做爲一個例子,來還原Chrome DevTools Extension的編寫方法。
爲此,咱們先熟悉幾個基本的概念。github

(1)tab頁

Chrome瀏覽器是由tab頁組成的,一個瀏覽器實例中能夠打開多個tab頁。web


 
 

(2)DevTools Window

每一個tab頁,均可以打開本身的開發者工具窗口,稱爲DevTools Window。chrome


 
 

注意,每一個tab頁都有本身獨立的DevTools Window,
只是切換tab頁的時候,只會顯示當前tab頁的DevTools Window。數據庫

(3)DevTools Page 和 Panel

下面咱們來建立一個Chrome DevTools Extension項目,目錄結構以下,

chrome-devtools-extension-example
├── devtools.html    // DevTool Page ├── devtools.js // DevTool Page中引用的js ├── manifest.json // 入口 ├── panel.html // 開發者工具欄選項卡頁面 └── panel.js // 選項卡頁面中引用的js 

其中manifest.json是入口,它會聲明一個對用戶不可見的DevTools Page。
在本例中爲devtools.html

{
  "name": "PageRecorder", "version": "1.1.0", "minimum_chrome_version": "10.0", "description": "Record all http requests in a page.", "devtools_page": "devtools.html", "manifest_version": 2 } 

DevTools Page引入的js,具備訪問DevTools API的能力,
包括上文提到的那些API,devtools.inspectedWindowdevtools.networkdevtools.panels

DevTools Page對用戶是不可見的,若是須要在開發者工具欄中建立新的DevTool選項卡,
還須要在DevTools Page使用一下方法來建立,DevTool選項卡,官方稱爲Panel。
原生的Panel包括,Elements,Console,Network,等等。

// 建立一個Panel chrome.devtools.panels.create( // title 'ChromeDevToolsExtensionExample', // iconPath null, // pagePath 'panel.html' ); 

以上,咱們在DevTool Page中建立了一個新的Panel,名字爲ChromeDevToolsExtensionExample

 
 

 

其中,panel.html,咱們只是簡單的寫了一個Hello World!
值得注意的是,每一個Panel均可以加載本身的html,js和css,且具備和DevTools Page同樣的權限。

(4)Panel的生命週期

Panel只有在第一次被激活的時候,才進行實例化,
同一個DevTools Window中的不一樣Panel切換時,不會從新加載。
當前tab頁刷新時,Panel也不會從新加載。

DevTools Window關閉後,Panel將被銷燬。

所以,咱們要想使用Chrome DevTools Extension,就必須先打開開發者工具窗口,
而後再激活咱們新建的DevTools Panel。

3. 監聽請求

 
 

上文咱們提到了,Chrome DevTools Extension能夠訪問devtools.network API,
如今咱們來展現使用chrome.devtools.network.onRequestFinished.addListener來獲取請求。
爲此,咱們新建了一個panel.js文件,並在panel.html中引用它。

// Chrome DevTools Extension中不能使用console.log const log = (...args) => chrome.devtools.inspectedWindow.eval(` console.log(...${JSON.stringify(args)}); `); // 註冊回調,每個http請求響應後,都觸發該回調 chrome.devtools.network.onRequestFinished.addListener(async (...args) => { try { const [{ // 請求的類型,查詢參數,以及url request: { method, queryString, url }, // 該方法可用於獲取響應體 getContent, }] = args; log(method, queryString, url); // 將callback轉爲await promise // warn: content在getContent回調函數中,而不是getContent的返回值 const content = await new Promise((res, rej) => getContent(res)); log(content); } catch (err) { log(err.stack || err.toString()); } }); 

以上就是panel.js的完整內容了,咱們還須要作如下幾點說明,

 
 

 

(1)Chrome DevTools Extension中,不能直接使用console.log
因此本例中使用了devtools.inspectedWindow API中的chrome.devtools.inspectedWindow.eval方法,
在當前審查的窗口中直接求值一段js代碼,從而間接實現打印日誌的功能。

(2)與獲取http請求的methodqueryStringurl不一樣的是,
咱們須要調用getContent方法來獲取http響應體,
而且,getContent是一個高階的異步函數

所謂高階函數,指的是,它接受一個回調函數做爲參數getContent(content=>{ })
這個回調函數的參數content,纔是對應http請求的響應體。

所謂異步,指的是,當回調函數還沒觸發的時候,getContent就已經返回了。
這也致使了事件監聽函數,也不得不具備異步性。

(3)因爲事件監聽函數是異步的,
因此,有可能在上一個onRequestFinished事件還未處理完的狀況下,
下一個onRequestFinished的監聽函數就又被觸發了。

這就致使了,以上例子中,log(method, queryString, url);log(content);
多是亂序打印的。

這個問題咱們曾經討論過,可參考:怎樣按觸發順序執行異步任務

總結

到此爲止,咱們最簡版的Chrome DevTools Extension示例已經介紹完了,
如下是能夠運行的源碼地址:github: chrome-extension-example
(注:不是master分支,而是simply分支。

Chrome擴展遵循一種優秀的設計原則,
那就是在設計系統的時候,應該想辦法讓擴展對用戶而言,與原生功能平權。 這種對稱性,會拉近原生與擴展之間的距離,從而讓系統架構從一開始就創建在靈活的基礎之上。

做者:何幻 連接:https://www.jianshu.com/p/4ce7f58b8c84 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
相關文章
相關標籤/搜索