當前位置: 妍妍網 > 碼農

餵到嘴裏,自整合式 HTTP 代理方案

2024-06-07碼農

架構師(JiaGouX)

我們都是架構師!
架構未來,你來不來?

前言

大部份程式設計師,想必都會有一個常用的抓包代理工具;

但在座的各位,可曾見過這樣一款 整合在 Web 套用中 的代理工具?

它是明顯區別於傳統代理工具的,有以下特性:

  • 零安裝、零配置 ,Web 點選即用、APP 掃碼即用;(不是開蓋即食,而是直接餵到嘴裏)

  • 分享 URL 連結(或二維碼),即可 遠端偵錯 HTTP 協助他人或偵錯行動裝置

  • 使用者可 遠端相互共享代理配置 ,無需手動匯入匯出

  • 以一個場景舉例

    1. 你是一個前端開發,當後端介面還沒準備好(或有 Bug 時),產品或設計師想體驗效果

    2. 傳統辦法,你配好介面 Mock,讓產品使用你的裝置體驗

    3. 當前方案,你配好介面 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 等)沒有任何沖突,不會影響習慣使用通用代理工具的同學。

    接下來介紹該方案的技術實作思路。



    方案原理概覽



    總結分為四個部份

    1. 與套用整合,將請求轉發到代理服務,由代理服務轉發請求到目標服務

    2. 代理服務提供網路偵錯界面(UI),允許使用者檢視網路請求、配置 Mock 規則

    3. 代理服務記錄請求,並同步到 UI 界面

    4. 代理服務在轉發請求前、收到響應後,按 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 配置以降低使用門檻。

    規則解析

    1. 定義規則語法

    2. 使用 [peggy][4] 按語法將字串解析為 AST(抽象語法樹)

    3. 將 AST 轉換為 js 函式實作

    4. 函式會檢測代理的請求是否命中規則,命中後按規則描述篡權請求內容

    規則相對簡單,使用語法解析是為了保持擴充套件性,字串處理多寫幾個條件判斷也能實作。

    數據儲存

    數據(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]