nginx 1.31.5 落地笔记:谓词 location、提前读 body、原生 JSON 与 Control API
nginx 1.31.5(2026-09-02 mainline)的 CHANGES 里有四条 Feature:Control API(从 F5 NGINX Plus 开源)、predicate locations、ngx_http_json_module、client_body_early_read。后三条互相咬合,真正上线时要考虑的更多是代价,而不是「有没有」。
谓词 location:路由不再只按 URI
location 里可以直接写变量:
map $http_user_agent $is_ai_scraper {
default 0;
"~*(gptbot|claudebot)" 1;
}
server {
location $is_ai_scraper {
return 403;
}
}
变量来源可以是 L4 网段、客户端证书、L7 请求头或自定义业务逻辑。好处是路由条件从「URI 字符串」扩展到「请求属性」,坏处是求值时机必须自己确认:哪些变量在 location 匹配阶段已经可用,哪些要等 rewrite/access 阶段才填充。用错阶段的变量,谓词会稳定地取到空值,而且不报错。
client_body_early_read:把 body 读在匹配之前
默认流程是先读请求头、选出 location、再缓冲请求体。开启后强制在 location 匹配之前完成请求体的缓冲与解析。
代价有三块:
- 内存。提前缓冲的 body 占用
client_body_buffer_size;超过部分按 nginx 常规行为写入client_body_temp_path。 - 大文件与流式请求。上传、streaming、SSE 之类本来不需要在匹配前拿到 body 的请求,现在会先落盘再继续,磁盘 IO 与延迟都会上来。
- 限额保护。请求体在 location 匹配前就被读,如果
client_max_body_size只在某个 location 里收紧,这个限制就落在读之后——前置读取阶段没有对应的 location 级保护。要么在更外层统一收紧,要么接受这段窗口。
server {
client_body_early_read on;
client_body_buffer_size 64k;
client_max_body_size 1m;
}
json_set:只能解析已缓冲的 body
原生 JSON parser 把已缓冲 payload 的字段提取成 nginx 变量:
json_set $json_method $request_body "method";
因为作用对象是「已缓冲」的 body,这个模块实际上必须配 client_body_early_read。配上之后,JSON 变量在 location 求值前就已填充,于是可以直接当谓词用:
location $json_method {
# 按 payload 里的 method 分流
}
提取出的变量也能喂给 map,做边缘校验或限流键。这套能力以前要靠 njs(如 MCP Observability Module)或 Lua 实现,现在是核心模块。
组合起来适合什么
/mcp、/api/v1、/graphql 这类同一 URI 上跑不同操作的 API 与 agent 流量:按 payload 路由、按 payload 做边缘校验,都不用再引入脚本层。前提是请求体小、结构稳定,并且能接受「匹配前先读 body」的成本。
上线前验证清单
nginx -t过配置,同时确认谓词里用到的变量在该阶段确实有值(打日志验证,不要靠推测)。- 用
curl构造同 URI 不同 payload 的请求,对比分流结果;用ab或类似工具压一轮,看开启 early_read 前后的延迟与错误率。 - 观察
client_body_temp_path下的临时文件增长,以及 worker 进程内存,确认client_body_buffer_size/client_max_body_size的组合处在可接受区间。
1.31.5 其他改动
FastCGI/uWSGI 支持多字节参数名长度;memcached 尊重最大长度结束标记;QUIC 拒绝 1-RTT 包中的 CRYPTO 帧;slice filter 增加溢出保护;event pipe 不再释放下游仍在使用的 buffer;core 把 channel fd 接收错误改为非致命。
同分支后续版本
1.31.7(2026-10-14):原生 GeoIP 模块支持 MaxMind MMDB,geoip_country/geoip_city/geoip_org 指向 .mmdb;$geoip_country_code3 由内置 ISO 表推导,$geoip_org 依次查 autonomous_system_organization/isp/organization/domain,$geoip_dma_code 可能为空,$geoip_area_code 永不设置。HTTP/2 实现 RFC 9218 优先级(Priority: u=1 / u=5, i),旧的 RFC 7540 依赖树与权重被移除、旧优先级信号被忽略;测试中 50Mbit/s 链路上两个 10MB 下载,后发的 u=1 请求 2.57s 完成,先发的 u=5 请求 3.42s 完成。QUIC 的 BPF reload 与二进制升级也有改进。
1.31.8(2026-10-21):working_directory 路径改为相对 nginx prefix;修复严格对齐平台上的 HTTP/3 SIGBUS;OpenSSL 3.2+ kernel TLS 关闭 SSL 连接时的 recv() EIO 告警。
安全修复(1.30.6 / 1.31.7,2026-10-14):alias+rewrite 缓冲区溢出 CVE-2026-15176、字符串表达式求值缓冲区溢出 CVE-2026-93479、HTTP/3 请求体注入 CVE-2026-95101、TLS session ticket key 轮换导致会话伪造 CVE-2026-97629、ngx_http_ssi_module 与 AIO 的 use-after-free CVE-2026-97205。