ByteScope

524

HTTP 524 A Timeout Occurred 怎麼修

5xx 伺服器錯誤非標準Cloudflare

Cloudflare 自己的代碼,用在一個一路進得去、然後就沒聲音的請求上:連線成功了、來源機收到了,而 125 秒之後還是沒有任何 HTTP 回應可以送回來。

為什麼會看到 524,以及該怎麼處理

同樣三個數字,你站在請求的哪一邊,它就是不同的問題。直接讀你自己那一塊。

用 curl 重現 524

對著出錯的那個網址跑一次。它只印狀態碼、不印錯誤頁,所以你看到的是伺服器真正說了什麼,而不是瀏覽器畫出來的東西。

curl
curl -sS -o /dev/null -D - --max-time 300 -w '\n%{http_code} connect=%{time_connect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n' https://example.com/slow-report

`--max-time 300` 是 curl 對整個操作的上限,而且它必須明顯高於 125 秒,否則會是 curl 先放棄,那你量到的是自己的耐心、不是 Cloudflare 的。524 在那份輸出裡的形狀非常好認:`connect` 只有零點幾秒,`ttfb` 和 `total` 都在 125 秒附近,而狀態碼是 524——一次很快的連線,接著一段很長的沉默,而這正是它跟 522 的分野,522 是連線本身從來沒完成。接著用 `--resolve example.com:443:203.0.113.10` 指向你的來源機位址,把邊緣節點從路徑上拿掉,再跑一次同樣的請求。如果來源機在 200 秒之後回答了,那就是這件事真的那麼慢,524 是一份準確的報告;而 curl 印出來的那個數字,就是這個請求真正需要的時間,也是你該拿來設計的數字。如果繞過邊緣之後來源機很快就回答,那多出來的時間是加在應用程式前面的——某個 Worker、某條 WAF 規則,或是連往來源機的 HTTP/2——那來源機就不是該看的地方。跑指令的同時盯著來源機自己的存取紀錄:一個出現在那裡、耗時超過 125 秒的請求,就證明了那件事是在 Cloudflare 不再聽之後才完成的,而這正是 524 之後重試寫入不安全的原因。而一個在那份紀錄裡從頭到尾沒出現的請求,代表它被排隊、從來沒開始,那個端點並不慢——是伺服器滿了。

524 實際上在講什麼

524 不是 IETF 的狀態碼——登記的 5xx 範圍到 511 為止,520 到 526 屬於 Cloudflare,只有 Cloudflare 的文件在定義,而且只會出現在真的有被代理的流量上。Cloudflare 的定義精確得不尋常,值得讀兩遍:錯誤 524 表示 Cloudflare 成功連上了來源網頁伺服器,但來源機在預設的 125 秒之前沒有提供 HTTP 回應。前半句就是診斷。連線成功代表來源機有在監聽、監聽的是 Cloudflare 會代理的連接埠,而且防火牆有放 Cloudflare 進來——521、522、523 會提出的每一個問題都已經有答案了,一個都不必再查。剩下的全在應用程式裡面。那 125 秒是 Cloudflare 的 Proxy Read Timeout,寫在它的連線限制參考文件裡;只有 Enterprise 方案的區域可以調整,透過 Cache Rules 或區域設定 API 最多拉到 6,000 秒——所以在其他所有方案上,這個數字是環境的既定事實,不是一個可以調的設定。Cloudflare 列了兩個原因——來源網頁伺服器上有長時間執行的程序,以及來源網頁伺服器過載——而這兩個從邊緣看起來一模一樣,實際上卻是不同的問題:前者是請求正在執行、只是比逾時久,後者是請求根本還沒開始,因為工作行程池滿了。Cloudflare 文件裡的解法也照同一條線分開:慢的那支程序去找主機商談;長時間的 HTTP 操作改成狀態輪詢,不要一直開著一個請求;真的合理超過 125 秒的東西搬到一個 DNS-only(灰雲)的子網域後面,讓它完全不經過代理;並且用 Origin Analytics 在回應時間逼近門檻、還沒越過去之前就先看到它爬上來。有一個從 RFC 9110 §15.6.5 那個一般 504 帶過來的性質,在這裡更重要,因為計時器實在太長了:Cloudflare 不再聽的時候,來源機還在做事,所以 524 不能當成「什麼都沒發生」的證據。

524 最常被搞混的幾個代碼

容易搞混的怎麼分
504504 是 RFC 9110 §15.6.5 的 IETF 代碼,給一台沒有及時收到回應的閘道用,任何代理都可以回它。524 是 Cloudflare 的,代表 Cloudflare 自己那 125 秒的 Proxy Read Timeout 走完了。所以一個穿過 Cloudflare 抵達的 504,是 Cloudflare 後面某個東西產生、再被轉過來的,這代表計時器在你自己的技術堆疊裡、不在他們那邊——而耗時會指認出它,通常是 nginx 或 Application Load Balancer 的 60 秒。
522兩個都是逾時,但它們量的是不同階段。522 是連線層級的:Cloudflare 的定義是送出 SYN 之後 19 秒內沒有 SYN+ACK,或連線建立之後 90 秒內請求沒被確認。524 是回應層級的,而且只有在上述全部成功之後才會發生。所以拿到 524 就等於證明了網路路徑、連接埠和防火牆全都正常,那是真的資訊,不是安慰。
521521 是拒絕,524 是沉默,兩者完全互斥。Cloudflare 把 521 定義成來源機拒絕它的連線,指向一個停掉的行程、錯的綁定位址、一個不在 Cloudflare 代理清單裡的連接埠,或一道拒絕 Cloudflare 位址範圍的防火牆。而 524 靠著「連線成功」這件事,已經把上面每一項都排除了——所以看到 524 之後還花時間在連接埠和防火牆上,那些時間都花在錯的問題上。
520520 是來源機回了一個 Cloudflare 用不了的東西——空的、未知的或非預期的,包括標頭超過它 128 KB 的上限;而 524 是來源機根本沒有及時回答。這個區別值得分清楚,因為兩邊的修法毫無共通之處:520 把你送去看你的應用程式吐出了什麼,包括格式壞掉的標頭和設定錯誤的 HTTP/2 to origin;524 則把你送去看它花了多久。
Cloudflare Tunnel來源機掛在通道後面,會改變你該去哪裡看,但不會改變那個計時器。125 秒的 Proxy Read Timeout 是「被代理的路徑」的性質,所以一個透過通道服務的請求撞到的是同一個上限,而連接器自己的紀錄就成了邊緣和應用程式之間的中間層。請把它跟來源機的存取紀錄一起看:一個出現在連接器紀錄、卻沒有出現在應用程式紀錄裡的請求,是被排在應用程式前面等,不是被應用程式拖慢的。
原因片語
A Timeout Occurred
類別
5xx 伺服器錯誤
定義出處
Cloudflare
標準
非標準

站上可以搭配的工具

這些全都在你的瀏覽器裡跑,不會上傳任何東西。

相關狀態碼

查 524 的時候,通常也會順手看一下這幾個。

常見問題

怎麼知道這個狀態碼是哪一台伺服器回的?

去讀回應標頭,不要讀那個網頁。curl -sS -o /dev/null -D - https://example.com/path 會只印標頭、不印內容,而 serverviacf-ray 三個加起來,就能指出是哪一層回答的。有 cf-ray 的值代表這個回應是 Cloudflare 處理的,那個值也是他們客服會跟你要的編號。想把邊緣節點整個排除掉,就加上 --resolve example.com:443:203.0.113.10 再打一次:它會照樣送出原本的主機名稱和 SNI,但直接連到你指定的來源位址——答案變了,就代表邊緣節點和來源機講的不是同一件事。

數字後面那句原因片語(像 Not Found)重要嗎?

不重要,而且絕對不要拿它來做判斷。RFC 9112 要求用戶端忽略原因片語,伺服器可以隨意改它,而 HTTP/2 和 HTTP/3 根本沒有這個欄位——所以在 HTTP/1.1 上是 404 Not Found,到了 HTTP/2 就只剩一個 404。這個網站會寫出登記在案的片語,是因為那是大家會拿去搜尋、也是會出現在 HTTP/1.1 紀錄裡的字串,不是因為有任何軟體依賴它。

這個代碼失敗的請求該不該重試?

5xx 和 429 可以重試,4xx 不要——下一次送過去也不會有任何不同。如果回應帶了 Retry-After 就照它做,RFC 9110 定義它就是為了這件事,值可以是秒數也可以是一個時間點。沒有的話,就用帶抖動的指數退避加上一個硬上限,而且只對冪等的方法這樣做:一個被重試的 POST 可能會刷兩次卡。對一台已經在失敗的伺服器丟出重試風暴,是短暫事故變成長時間事故最常見的那條路。

我可以讓自己的伺服器改回別的狀態碼嗎?

可以,唯一要守的規則是那個代碼必須是真的。所有會自動讀你回應的東西——搜尋引擎、監控、快取、用戶端的重試邏輯——都只看那個數字,從來不看那一頁寫了什麼。用 200 回一頁錯誤訊息,會把故障從你自己的警報裡藏起來;用 200 回一頁不存在的內容,會讓錯誤被當成內容收進索引;而對一個只是格式不對的請求回 500,會把值班的人送去堆疊裡錯的那一半。

524 還是卡住嗎?看完整的狀態碼對照表,或是回到上面,讀為你這一端寫的那一塊。