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响应示例
我们建议使用问题详情格式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