$request_length 是 nginx 内置变量,表示客户端发送的完整 http 请求字节数;可用于日志记录、限长拦截及结合其他变量识别异常大包,是防御 dos 等攻击的轻量级防线。

$request_length 是 Nginx 内置变量,表示客户端发送的整个 HTTP 请求(含请求行、请求头、请求体)的字节数,单位为字节。它不依赖于是否启用 body 缓存或是否读取了 request body,只要 Nginx 已接收并解析完该请求(包括已读取或跳过 body),该变量就准确反映原始请求总长度。利用它可有效识别异常大包,是防御 DoS、恶意上传、畸形请求的第一道轻量级防线。
在 access_log 中记录并筛选大请求
将 $request_length 加入自定义日志格式,便于后续分析:
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'$request_length $request_time "$http_referer" '
'"$http_user_agent"';然后在 server 或 location 块中启用:
access_log /var/log/nginx/access.log detailed;
之后可通过日志工具快速定位超长请求,例如:
# 查看大于 10MB 的请求(10485760 字节)
awk '$8 > 10485760 {print}' /var/log/nginx/access.log结合 limit_req 或 if + return 实时拦截超限请求
对明确不允许大请求的接口(如登录、API 查询),可在 location 中设置硬性限制:
- 使用 limit_req 配合 zone 和 burst,适合需限流+防突增场景(注意:limit_req 主要基于 key 限频,不是直接按长度拦截)
- 更直接的方式是用 if + return 拦截:
location /api/ {
if ($request_length > 2097152) { # 超过 2MB
return 413 "Request Entity Too Large";
}
proxy_pass http://backend;
}⚠️ 注意:if 在 location 外慎用;此处放在 location 内是安全的。返回 413 是语义最准确的状态码,客户端也易识别。
区分正常大包与恶意大包的常见模式
单纯设阈值可能误伤,需结合上下文判断是否异常:
- POST/PUT 请求体较大是合理的(如文件上传),但应限定在特定路径(如 /upload/)且配合 client_max_body_size
-
GET 请求出现超大 $request_length 很可疑(通常因 query string 过长或 header 注入),建议对所有非 POST/PUT 的请求统一限制,例如:
if ($request_method !~ ^(POST|PUT|PATCH)$) {
if ($request_length > 16384) { return 400; } } - 高频小请求突然夹杂单次超大请求,可能为探测或攻击,建议结合 $remote_addr + $request_length 统计分析
配合其他变量做关联判断提升准确性
单独看 $request_length 不够,建议组合使用:
- $content_length:客户端声明的 body 长度,若远小于 $request_length,说明 header 极大(可能是 header bomb)
- $request_uri 和 $args:检查 query string 是否异常冗长
- $http_content_type:非 multipart/form-data 却携带大 body,值得警惕
- $time_local 和 $remote_addr:用于聚合分析,识别 IP 级突发大包行为
例如,在日志中同时记录:
'"$request_uri" $request_length $content_length "$http_content_type"'











