AAD Token 太大讓 nginx HTTP/2 直接 GOAWAY
前言
在最近的專案中,心血來潮在所有呼叫公司內部 API 的 header 都加上 AAD token, 結果其中一個服務的 API 直接掛掉,從瀏覽器中只看到 ERR_CONNECTION_CLOSED,而後端用 Swagger 測試正常,去看 Nginx 的 Access log 和 Error log 都沒有紀錄。
奇怪到底發生什麼事?
除錯過程
已知線索
目前已知的線索有:
- Preflight 有過
- Swagger 可以通但是從應用程式送請求會沒有回應
- Nginx 的 Access Log 和 Error Log 都沒有紀錄
初步懷疑
懷疑的幾種可能:
- 有人改到 Access-Control-Allow-Origin header 讓 CORS 請求不會過
- 公司的 Proxy 攔截到 AAD token 後做了什麼事
- Load Balancer 或是 Nginx 出問題
抓到 GOAWAY
測試的過程使用 Opencode 搭配 Opus 來說真的非常爽快,對於我提出的懷疑這個組合都能夠直接使用指令來測試,在用 Curl 帶 Token 測試的過程中,發現了新的線索:
1 | |
看到了關鍵字 GOAWAY 以及 error=11 代表 ENHANCE_YOUR_CALM ,這個是 HTTP/2 中,伺服器認為用戶端可能會造成負載過高,通知用戶端即將關閉連線。
確認 nginx buffer 設定
有了這個線索後,可以懷疑是 Nginx 的問題,因為是加了 header 打不過,在 Config 中看到了亮點:
1 | |
分別做了以下兩個測試分別都通過了
- 在應用程式前端中拿掉 Bearer token 後呼叫 API
- 在後端把 buffer size 加大
測試 header 大小
後來又多做了幾個測試來測不同 header 大小
1 | |
發現 2000 以下的都可以通過,至於 1500 為什麼可以通過猜測是有經過壓縮,但我沒有驗證。
到這邊可以確認 Root Cause 就是 Nginx 的 large_client_header_buffers 上限被踩到,造成連線中斷。
HTTP/1.1 對照
有趣的是,如果我們強制使用 HTTP/1.1 連線,會得到 400 而且明確標示 Request Header Or Cookie Too Large
1 | |
小丑竟是我自己
這次的問題不好查有一部分原因是 GOAWAY 這個 frame 在瀏覽器根本不會顯示,加上 Nginx 沒有 log 可以看,只能旁敲側擊。
好在現在用 AI 來除錯真的很方便快速,所有工具唾手可得很快就能驗證想法。
後來去看了為什麼 buffer size 會被改成 1K,git blame 結果居然是我自己用 AI 產的 config…
再次驗證了 AI 寫出來的東西每一行都還是要看懂。