431 HTTP狀態碼,亦稱為「請求標頭字段過大」,是一種客戶端錯誤,表示服務器拒絕處理請求,因為其標頭字段過大。此錯誤可能由標頭總大小或單個標頭字段超出允許大小引起。
HTTP 431狀態碼首次引入於RFC 6585,該文於2012年4月發布。這是標準化HTTP/1.1額外回應的一部分,解決了當時現有狀態碼未涵蓋的問題。引入此特定錯誤碼對增強服務器安全性和防止如緩衝區溢出攻擊等惡意攻擊至關重要,這些攻擊可能利用大標頭。
理解HTTP 431錯誤
當發生431錯誤時,意味著服務器因標頭字段過大而阻止了客戶端的請求。每個服務器對HTTP標頭字段的最大允許大小都有自己的政策,這有助於防止服務拒絕攻擊。
HTTP 431錯誤的常見症狀
- 請求標頭的總大小過大:當所有請求標頭的累積大小超出限制時,會發生此錯誤。
- 單個標頭字段的大小過大:在此情況下,單個標頭字段過大而無法處理,導致431錯誤。
HTTP 431 錯誤的常見原因
- 過多Cookie:擁有過大或過多的Cookie會導致431錯誤。這可能發生在相同Cookie被多次設置,或單個請求或響應中合併了多個Cookie的情況。一個常見的場景是在多個專案中重用同一個
localhost
端口,並將所有這些專案的Cookie隨請求一起發送。 - 不當的標頭字段緩存:不正確地緩存大標頭可能導致431錯誤。不當緩存會增加標頭大小,導致緩衝區溢出。
- 不必要的或格式不當的請求標頭:過度使用HTTP標頭可能導致請求超過服務器設置的大小限制,從而引發431響應。此外,請確保您的標頭格式正確。擁有過長的
Referer
URL也可能觸發431。
如何避免431錯誤
清除Cookie
定期在客戶端清除Cookie(Chrome開發工具 > 應用 > Cookie),並限制服務器上使用的Cookie數量。
緩存標頭
正確實施標頭快取以確保快取的標頭反映實際請求和壓縮響應。如果您重度依賴ETags進行條件請求,請調整ETags,因為大型ETags可能導致錯誤。
最小化HTTP標頭
簡化您的HTTP標頭,只包括必要的資訊。避免包含冗餘的元數據,特別是在Authorization、Referer和User-Agent等標頭中。
壓縮標頭大小
有時候,您發送的標頭不足,而標頭因為不受您控制的約束而過於龐大(例如,您的JWT令牌編碼了大量資訊)。標頭壓縮可以顯著減少請求標頭的大小。利用HTTP/2和HTTP/3等協議,這些協議預設支持標頭壓縮。這可以自動減少標頭大小,而無需額外配置。
處理伺服器最大標頭大小限制
HTTP規範未定義標頭大小的限制;然而,許多伺服器確實有此限制。以下是一些流行網頁伺服器/主機的限制:
- Apache: 8K
- nginx: 4K-8K
- IIS: 8K-16K
- Tomcat: 8K-48K
- Node: (<13) – 8K; (>13) – 16K
- Cloudflare: 每個標頭16K,總共32K
大多數伺服器允許某種形式的配置,不同版本的伺服器軟件可能具有較低或較高的限制。您還應該查閱最新的文檔,以了解這些限制是否包括請求的其他部分(例如,cookie)或僅限於常規標頭。
增加請求標頭大小限制
有時,增加請求標頭大小限制可能是必要的。您通常可以通過伺服器的網頁控制台或CLI來完成這一操作。如果您在本地開發,通常有CLI標誌可以配置此值。以下是在Node JS中配置請求標頭大小限制的標誌:
--max-http-header-size=16384
注意:增加標頭大小限制應謹慎進行,因為更大的標頭可能會消耗更多內存並降低性能。
如何發送HTTP 431錯誤響應
您可能不希望依賴伺服器來確定您的請求標頭大小限制,或者您可能希望為每個API端點強制執行自定義的標頭大小限制。請按照以下步驟了解如何發送您自己的431錯誤。
在您的API中構建請求標頭大小限制
如上所述,您的宿主 + 伺服器組合可能會自動強制執行一個限制。要在您的API中構建自定義請求標頭大小限制功能,您可以使用Node.js中的庫,如express
。以下是說明如何啟用對請求標頭大小限制的示例:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
const headerSizeInBytes = JSON.stringify(req.headers).length;
const maxHeaderSizeInBytes = 2000; // example limit
if (headerSizeInBytes > maxHeaderSizeInBytes) {
res.status(431).send("Request Header Fields Too Large");
} else {
res.send("Hello World!");
}
});
app.listen(3000, () => {
console.log("Server is running on port 3000");
});
區分請求標頭總大小與單個標頭字段之間的錯誤響應
在處理HTTP 431錯誤時,請確保區分兩種情況的響應:
- 請求標頭總大小過大:返回一個指示標頭累積大小過大的響應。
- 單個標頭字段的大小過大:在此情況下,提供一個錯誤響應,指出哪個特定標頭字段超出了允許的大小。
修改上一節的示例以實現差異化錯誤響應:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
const headerSizeInBytes = JSON.stringify(req.headers).length;
const maxHeaderSizeInBytes = 2000; // example limit
const exceededHeaderField = Object.keys(req.headers).find(
(key) => req.headers[key].length > maxHeaderSizeInBytes * 0.1, // example individual field limit
);
if (exceededHeaderField) {
res
.status(431)
.send(
`Size of Individual Header Field '${exceededHeaderField}' Too Large`,
);
} else if (headerSizeInBytes > maxHeaderSizeInBytes) {
res.status(431).send("Total Size of Request Headers Too Large");
} else else {
res.send("Hello World!");
}
});
app.listen(3000, () => {
console.log("Server is running on port 3000");
});
HTTP 431響應示例
我們建議使用Problem Details格式API響應來回應您的用戶。
HTTP/1.1 431 Request Header Fields Too Large
Content-Type: application/problem+json
Content-Language: en
{
"type": "https://httpproblems.com/http-status/431",
"title": "Request Header Fields Too Large",
"detail": "Size of individual header field 'referer' too large",
"instance": "/account/12345/msgs/abc",
"trace": {
"requestId": "4d54e4ee-c003-4d75-aba9-e09a6d707b08"
}
}
讓您的閘道處理請求標頭大小限制
如果您使用API閘道,可以輕鬆將策略添加到請求管道中以處理此問題。以下是使用Zuplo的操作方法:
在路由設計器中導航到您的路由,並在請求管道上點擊添加策略。
在選擇策略模態中,我們有兩個選項,具體取決於您想要執行的操作。
結論
HTTP 431 錯誤通常是由過大的請求標頭觸發的。您可以通过優化標頭、根據需要進行壓縮,以及在您的 API 中實施請求標頭大小限制來避免遇到此錯誤。
此外,在您的 API 中實施標頭大小限制檢查也很簡單。大多數服務器已經包含默認值,您也可以在 API 路由內從累計和個別標頭層面自行設置。
Source:
https://dzone.com/articles/understanding-the-http-431-error