前言
大部份程式設計師,想必都會有一個常用的抓包代理工具;
但在座的各位,可曾見過這樣一款 整合在 Web 套用中 的代理工具?
它是明顯區別於傳統代理工具的,有以下特性:
零安裝、零配置 ,Web 點選即用、APP 掃碼即用;(不是開蓋即食,而是直接餵到嘴裏)
分享 URL 連結(或二維碼),即可 遠端偵錯 HTTP 協助他人或偵錯行動裝置
使用者可 遠端相互共享代理配置 ,無需手動匯入匯出
以一個場景舉例
你是一個前端開發,當後端介面還沒準備好(或有 Bug 時),產品或設計師想體驗效果
傳統辦法,你配好介面 Mock,讓產品使用你的裝置體驗
當前方案,你配好介面 Mock,發一個 URL 連結給產品即可遠端體驗
它的原理是將代理服務與套用(Web 網頁或 APP)整合,從而大幅降低使用者(研測產運)的使用成本。
套用整合代理服務對應的 SDK,自動轉發請求到代理服務
傳統代理工具的主要成本
下載安裝代理程式,甚至收費
配置系統代理(移動端更煩)、https 證書
同事之間共享代理規則(手動匯入匯出檔)
這些成本帶來各種煩惱,也將非技術崗位拒之門外。
場景:中午去吃飯的時候,手機突然斷網;原來是剛剛網路偵錯,配置了系統代理!
筆者曾嘗試過多款代理工具,始終有不滿意的地方,多年前在自己的開源計畫 [Erra][1] 中探索新的代理方案,仍然不滿意,遂放棄。
現將 Erra 的代理服務與工作中的套用整合,借鑒 [whistle][2] 的規則,再重新實作 UI 互動,終覺尚可。
以下對比筆者曾長期使用過的代理工具。
Charles | LightProxy | FF-Proxy | |
下載安裝 APP | 是 | 是 | 否 |
配置作業系統代理 | 是 | 是 | 否 |
安裝信任 HTTPS 證書 | 是 | 是 | 否 |
Mock 方式 | UI | 文本規則 | UI + 文本規則 |
Mock 規則共享 | 匯出規則檔 | 復制規則文本 | 線上分享 |
遠端偵錯 | 否 | 否 | 是 |
通用 HTTP 請求代理 | 是 | 是 | 否 |
安裝部署服務 | 否 | 否 | 是 |
該方案改進了工作中高頻對特定套用(公司產品的網域名稱、APP) 進行網路偵錯的體驗和效率;
該方案是一個 增強型能力 ,與通用代理工具(Charles、LightProxy 等)沒有任何沖突,不會影響習慣使用通用代理工具的同學。
接下來介紹該方案的技術實作思路。
方案原理概覽
總結分為四個部份
與套用整合,將請求轉發到代理服務,由代理服務轉發請求到目標服務
代理服務提供網路偵錯界面(UI),允許使用者檢視網路請求、配置 Mock 規則
代理服務記錄請求,並同步到 UI 界面
代理服務在轉發請求前、收到響應後,按 Mock 規則篡改請求內容
套用整合
與套用整合是當前方案區別與代理工具的根本所在,也是能 實作零安裝、零配置便捷性的原因 。
整合是 將代理服務對應的 SDK 註入到業務系統 (網頁或 APP)中,SDK 會攔截並轉發請求到代理服務。
整合 SDK 的方式介紹以下兩種,更多攔截註入技巧請閱讀 [ ][3]。
自動註入 SDK
1. 配置 DNS 使 `ff-*` (混合泛解析)指向代理服務,代理轉發 html 請求時自動註入 SDK
註入指令碼範例`resp.body.replace('<head>', '<head><script src="/ff-sdk.js"></script>')`
2. 假設目標網域名稱為 `live.bilibili.com`,使用 `ff-live.bilibili.com` 存取代理服務即可自動註入
該方式無需業務計畫對接, 適合多個網域名稱(系統)需要接入 的場景。
註:ff-sdk.js 即需要註入,在客戶端環境執行的的 SDK
手動註入 SDK
手動往前端計畫的 HTML 中寫入`<script src="/ff-sdk.js"></script>`
,或打包構建時自動註入。
若 接入計畫較少,或沒有 DNS 配置許可權 ,則可采用該方式接入。
攔截轉發請求
向頁面註入 SDK(`ff-sdk.js`)後, 根據 URL Query 參數決定是否開啟攔截轉發請求。
若 URL 參數包含 `ff-proxy-id` 即啟動攔截轉發,參數值是隨機生成 id,用於隔離不同使用者數據。
攔截轉發的實作原理是重寫 `fetch, xhr, WebSocket` 等物件,將請求轉到代理服務,如何轉發請看下文 請求變換協定 ;
另外還需要重寫 `open, a, iframe` 的目標連結,確保頁面跳轉(或嵌入)場景也能繼續保持 URL 字首(`ff-`)和 Query 參數(`ff-proxy-id`) 的狀態。
// 介面效能監控,開啟 https://example.com/, 在控制台執行以下程式碼
const _fetch = window.fetch;
window.fetch = (...args) => {
const startTime = performance.now();
return _fetch(...args).finally(() => {
console.info('介面耗時:', Math.round(performance.now() - startTime), 'ms');
});
};
await fetch('//example.com');
重寫系統 API 以實作攔截的更多技巧,請閱讀 [ ][3]。
移動端 APP 支持
1. 向網路庫註冊一個攔截器
2. 掃描特制的二維碼後,攔截器開始轉發請求
3. 掃碼後 APP 還需要修改 WebView 容器的 URL,添加字首(`ff-`)和 Query 參數
- 字首和參數的內容在二維碼中獲取
HTTP 請求變換協定
SDK 攔截 HTTP 請求轉到代理服務,然後還原再轉到目標服務,其關鍵在於 變換與還原請求的協定 。
原始請求,直接指向目標服務 (_以 curl 風格描述請求_)
`curl -v https://api.live.bilibili.com/test`
URL 添加字首 `ff-` 請求會轉到代理服務,因為代理服務註冊了 DNS 混合泛解析規則`ff-*` ;
再添加 HTTP Header `x-ff-proxy-id` 用於隔離不同使用者的數據。
`curl -v 'http://ff-api.live.bilibili.com/test' -H 'x-ff-proxy-id: xxx'`
代理服務 移除 URL 中的字首與 Header,即還原成原始請求 ,再發送給目標服務;
同時,根據 `x-ff-proxy-id` 將該請求同步給對應 UI 界面。
代理服務與 UI 互動
代理服務作為遠端中心節點,跟客戶端(UI界面)使用 WebSocket 保持通訊,代理服務會按照 `ff-proxy-id` 只同步當前使用者的數據,封包括抓包記錄、Mock 規則、資源。
資源是用來管理內容較大的 Request、Response body,方便用於 Mock 替換 HTTP 內容。
透過 URL `ff-proxy.bilibili.com/ui/` 即可存取 UI 界面。
抓包
代理服務每次代理請求都會根據 `ff-proxy-id` 的值,將請求內容 copy 一份發送給客戶端,這就實作了遠端偵錯。
所以該方案實作遠端偵錯是非常自然的,傳統代理工具相對麻煩是因為它工作在使用者的裝置上,遠端偵錯必須透過手動設定系統代理來實作連線。
比如,手機上存取介面
`curl -v 'http://ff-api.live.bilibili.com/test' -H 'x-ff-proxy-id: xxx'`
任何使用者在任何裝置上開啟了 `ff-proxy.bilibili.com/ui/xxx` 頁面, 即可遠端看到請求的詳細內容。
Mock 規則
代理服務還能接受客戶端送出的 Mock 規則,在 轉發請求前、收到響應後 ,按規則篡改請求內容。
支持對 HTTP 請求內容的基本修改(添加、刪除、替換),即可滿足絕大部份 Mock 訴求;
HTTP 請求內容指
Request: URL、Header、Body,
Response: StatusCode、Header、Body
規則借鑒了 [whistle][2] 並做了大量簡化,同時也提供 UI 配置以降低使用門檻。
規則解析
定義規則語法
使用 [peggy][4] 按語法將字串解析為 AST(抽象語法樹)
將 AST 轉換為 js 函式實作
函式會檢測代理的請求是否命中規則,命中後按規則描述篡權請求內容
規則相對簡單,使用語法解析是為了保持擴充套件性,字串處理多寫幾個條件判斷也能實作。
數據儲存
數據(Mock 規則、資源)儲存在瀏覽器的 indexedDB 中,每次連線時同步到代理服務進行解析;
所以,代理服務是一個幹凈的、只維持臨時狀態的服務,非常方便部署與擴充套件。
相對傳統代理的缺點
方案的優點寫在了文章開頭,這裏有必要總結一下缺點,感興趣的同學自行斟酌。
需要部署、維護代理服務
該方案 以系統維護者的一次性部 署成本,交換多個使用者安裝、配置軟體的成本
有一定侵入性
該方案不 是一個 透明的中間節點,會修改業務系統的行為(註入 S DK 攔截轉發)
PS: DNS 整合方式,可讓業務系統無感自動 接入, 最小 化影響
不具備通用性
該方案無法偵錯系統網 絡請求,無法偵錯未接入的業務系統、APP
總結
該方案的原理是將代理服務與套用整合,從而改進了 工作中高頻對特定套用 進行網路偵錯的體驗和效率。
所以,實施的前提是:一定的團隊規模讓(效率體驗改進) 收益大於付出 (代理系統部署維護成本)。
附錄
[Erra][1]: Node.js 實作的代理工具,已廢棄
[whistle][2]: 基於 Node 實作的跨平台抓包偵錯工具
[Web 終極攔截技巧(全是騷操作)][3]
[peggy][4]: Parser generator for JavaScript
[1]: https://github.com/hughfenghen/erra
[2]: https://github.com/avwo/whistle
[3]: https://hughfenghen.github.io/posts/2023/12/23/web-spy/
[4]: https://github.com/peggyjs/peggy
如喜歡本文,請點選右上角,把文章分享到朋友圈
如有想了解學習的技術點,請留言給若飛安排分享
因公眾號更改推播規則,請點「在看」並加「星標」 第一時間獲取精彩技術分享
·END·
相關閱讀:
作者:風痕、莫小謙
來源:嗶哩嗶哩技術
版權申明:內容來源網路,僅供學習研究,版權歸原創者所有。如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝!
架構師
我們都是架構師!
關註 架構師(JiaGouX),添加「星標」
獲取每天技術幹貨,一起成為牛逼架構師
技術群請 加若飛: 1321113940 進架構師群
投稿、合作、版權等信箱: [email protected]