人人都需要一個 HTTP proxy 來 debug

前言

介紹了作爲前端工程師如何使用 HTTP proxy 來進行 debug,超越了 DevTools 的限制。今日文章由前端早讀課 @huli 分享。

身爲每天都要與網頁打交道的前端工程師,熟悉 DevTools 的使用是相當合理的。每當接 API 出問題時,就按下快捷鍵打開 DevTools,切到 Network 分頁,找到紅色的那一行,右鍵複製成 cURL 粘貼到羣裏面,讓後端自己找找問題。

但不知道大家有沒有碰過 DevTools 不夠用的情況,這時該怎麼辦?

DevTools 真的會不夠用嗎?是不是你不會用?

舉幾個我實際碰過的案例,如果 DevTools 能解決那當然是最方便的,但我解決不了(也有可能是我不會用就是了)。另外,下面的 DevTools 指的都是 Chrome DevTools,或許其他瀏覽器的不會有這些問題。

重定向前的請求細節看不到

很多實現 OAuth 相關服務的網站在登錄完成後,會跳轉到 redirect url 並且帶着一個 code,而這時有些網站會拿 code 去交換 access_token,然後再帶着 access_token 跳轉到下一個頁面。如果 code 交換 access_token 這一步有問題,該怎麼 debug 呢?

Chrome DevTools 在跳轉到其他頁面時,默認會把 console 和 network 的東西都清空。有一個選項叫做「Preserve log」,把它勾起來以後看似問題就解決了,但其實沒有。

大家可以隨便找一個網頁,打開 DevTools 並且把保留 log 勾起來,然後執行以下代碼:

fetch('https://httpbin.org/user-agent')
.then(()=> window.location ='https://example.com')

當跳轉完成以後,雖然 Network 那邊確實可以看到這個請求,但點進去以後只會看到「Failed to load response data」:

看不到請求

這個問題從 2012 年就有人反饋了,好不容易等了十幾年,2023 年底時說這個在 2024 的 roadmap 上,但目前依然沒有任何動靜:DevTools: XHR (and other resources) content not available after navigation。

這個問題的本質是:一旦頁面跳轉,舊頁面的 Network 請求數據就會被瀏覽器丟棄。因此即使請求已經發送,DevTools 也無法保留或查看 Response。

總之呢,在這個情境之下,看不到 response 基本上沒辦法 debug,很不方便。

WebSocket 連接握手失敗找不到原因

雖然我們平常在用 WebSocket 時,只需要一行代碼就可以建立連接,但背後其實是分了兩步。

第一步會發出一個 HTTP Upgrade 請求,完成以後才切換到 WebSocket 連接。雖然大多數情況下第一步都會成功,那如果第一步失敗會怎樣呢?

我們可以請 AI 寫一個很簡單的 demo 出來:

等 AI 生成完之後用 docker 跑起來,一樣隨便開個網頁建立連接,會發現帶有 debug 的那個連接請求,你只知道失敗了,卻完全不知道原因:

看不到原因

這個錯誤信息甚至跟你隨便連一個沒開的端口一樣,完全不知道爲什麼會失敗,這樣也很難跟後端說問題在哪裏。

其實遇到 WebSocket 握手失敗,也可以嘗試用其他方式輔助調試,比如用 curl -i --include 手動模擬 HTTP Upgrade 請求,檢查是不是被後端或代理服務器攔截。這在無法獲取瀏覽器詳細錯誤信息時,是個不錯的替代方案。

以上是兩個我有印象的範例,但實際開發中應該碰過更多更多,基本上都是隻靠 DevTools 來看 Network 沒辦法解決的問題,要麼是看不到,要麼看到的東西不太對。

簡單好用的 HTTP Proxy

既然沒辦法靠 DevTools,那隻能依賴更底層的工具了,比如說 HTTP Proxy!有些工具會在你本機起一個 proxy,這樣流量就會都經過它,自然而然就能看到所有的請求了,就不必再受限於 DevTools。

HTTP Proxy 就像是你和網站之間的一箇中繼站:所有流量會先到 Proxy,再轉給目標服務器。這樣就能完整攔截、查看、甚至修改請求與響應內容。這也是爲什麼 Proxy 能突破瀏覽器 DevTools 的限制,直接拿到你想要的原始數據。

而且另一個好處是有地方可以互相對照,如果 proxy 顯示的跟 DevTools 顯示的不同,就有可能是 DevTools 顯示的東西有問題。

因此,誠心推薦大家找個 HTTP Proxy 來用,我自己用過的有這三個:

以前我剛接觸 proxy 時用的是 Charles,接觸到安全測試以後就改成用第二個 Burp Suite 了。它其實是個可以拿來做各種安全相關測試的工具,但我覺得你只拿來做 proxy 也沒問題,非常方便。

第三個 mitmproxy 是開源且免費的,知名度也很高,我偶爾也會用但是用的方式不太一樣,這個晚點再講。

把 Burp Suite 當 Proxy App 來用

先到官網下載安裝免費的社區版:https://portswigger.net/burp/communitydownload

打開之後按下 Next 然後 Start Burp,就會看到主畫面。你會發現它的功能很多,但我們先切到「Proxy」標籤下「HTTP history」這一頁就行了:

Burp 畫面

然後那顆很顯眼橘色的「Open Browser」點下去,就會開啓它自帶的 Chrome 瀏覽器,可以用這個瀏覽器訪問任何一個網頁,例如說 example.com。

接着切回工具,就會發現 HTTP history 裏面記錄着所有請求的原始內容和 response:

請求記錄

如此一來,前面提過的跳轉案例跟 WebSocket 握手失敗,都可以在這邊看到原始請求內容,錯誤一目瞭然:

原始內容

如果未來你碰到有些請求看不到,那就是被默認的 filter 篩選掉了,點 Filter settings 那邊選 show all 後 apply,應該就能看到了。

若是有碰到不安全的連接等問題,需要先安裝證書,請參考:Installing Burp’s CA certificate

以上就是 Burp Suite 作爲 HTTP Proxy 的基本介紹。如果你不想用它提供的 Chrome,也可以自己設置電腦或是瀏覽器的 proxy,它默認會在 8080 端口。

舉例來說,我在 Mac 上會再裝一個 Chrome Canary 專門拿來 debug,用這個指令可以開啓並且設置好 proxy 位置:

 open -a "Google Chrome Canary" --args --proxy-server="http://localhost:8080"

如此一來就能用自己熟悉的瀏覽器 debug 了。

話說 Burp Suite 還有很多其他功能啦,比如說重放請求或是暴力破解等等,不過我覺得一般工程師把它當 proxy 來用就已經幫助很大了。對完整功能有興趣的話可以參考 HackerCat 所寫的《Web 滲透測試 – Burp Suite 完整教學系列》。

用 mitmproxy 搭配腳本動態改變內容

mitmproxy 的安裝過程我就不多說了,可以參考官方文檔或是跟 AI 協作自己裝起來,安裝完之後也記得訪問一下 http://mitm.it 下載並安裝證書,才能攔截到 HTTPS 的流量。

都安裝完以後,執行 mitmproxy 就能夠把 proxy 跑起來了,會看到一個 CLI 的界面。

那既然 Burp Suite 已經很好用了,什麼時候會用到 mitmproxy 呢?它有個好用的功能是可以通過簡單的 Python 腳本去自定義 proxy 的行爲,非常方便。

舉例來說,假設因爲某些原因,測試環境無法完全模擬正式環境,但你又不可能直接把代碼上線到正式環境去測試。這時就可以用 proxy 動態替換 production 的 response,在本地模擬一些行爲。

雖然 Chrome 也有覆蓋 response 的功能,但限制比較多,比如說內容只能固定等等。我們自己用 proxy 搭配腳本,絕對是更靈活而且自由度更高的選擇。

下面是一個簡單的 mitmproxy 腳本,目的是把我博客的 script.js 用本地的來替換:

 from mitmproxy import http
import requests

URL_MAPPINGS={
"https://blog.huli.tw/js/script.js":"http://localhost:5555/script.js",
}

 def request(flow: http.HTTPFlow)-> None:
for url inURL_MAPPINGS:
if flow.request.pretty_url.startswith(url):
             replacement_url =URL_MAPPINGS[url]

             replacement_response = requests.get(replacement_url)

             flow.response = http.Response.make(
200,
                 replacement_response.content,
{"Content-Type":"application/javascript"}
)
return

用這個指令就可以跑起來:

 mitmproxy -s proxy.py

接着用前面講過的指令打開一個設置好代理服務器的瀏覽器:

 open -a "Google Chrome Canary" --args --proxy-server="http://localhost:8080"

再用瀏覽器訪問 https://blog.huli.tw,就能夠看出 script 的內容已經被替換。

結語

以上就是我平常自己會使用到的一些代理服務器以及使用方法。

太過依賴於瀏覽器不是件好事,只要瀏覽器沒有顯示,就不知道該怎麼辦。但前端工程師作爲第一線,絕對是有辦法拿到整個 request 與 response,才能進一步釐清問題。以後如果碰到瀏覽器上看不到請求的問題,可以試試看使用代理服務器來拿到完整的請求以及響應。

除了電腦的網頁之外,手機也可以使用,可以在 Android 上設置代理服務器連接到同一個 Wi-Fi 的電腦上,接着在手機上安裝證書,就能夠攔截手機的流量。

最後再講一個小技巧,在 Mac 的命令行執行指令時加上:

 https_proxy=http://localhost:8080

就能夠配置代理服務器,比如:

 https_proxy=http://localhost:8080 cursor

就可以把 Cursor IDE 的流量都導到代理服務器去。

關於本文
作者:@huli
原文:https://blog.huli.tw/2025/04/23/everyone-need-a-http-proxy-to-debug/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/wc5BDT0tsXpPkM3dSxRDag