关键不是设大 client_body_buffer_size,而是按真实流量 P95/P99 值精准设定(如 P95=120KB→设256k),避开 25% 自动余量临界点,并同步配置 client_max_body_size≥该值、client_body_timeout(15–30s)、client_body_temp_path(如 /dev/shm/nginx-body)及 debug 日志验证“buffered”行为。

让 Nginx 请求体尽量走内存、少写磁盘,关键不是把 client_body_buffer_size 设得越大越好,而是让它精准覆盖你业务中绝大多数真实请求体大小,并避开 Nginx 内部 25% 自动余量机制引发的“卡边落盘”。
按真实流量分布设值,跳过临界抖动点
Nginx 分配缓冲区时会自动加约 25% 余量(size += size >> 2)。比如你设 256k,实际尝试分配约 320k;但如果请求体是 319KB,它仍可能因内部逻辑退回到用原始 256k 分配,导致超出部分写磁盘。
- 从 access log 提取
$request_length或前端上报的Content-Length,统计 P95 或 P99 值 - P95 是 120KB → 推荐设 256k(而非 128k 或 255k),跳过 128k×1.25=160k、256k×1.25=320k 这两个易抖动临界区
- 纯 JSON 表单(含 JWT)通常 ≤100KB,设 128k 已足够;含 Base64 头像字段的表单,P95 常达 300–400KB,建议 512k
用 client\_max\_body\_size 主动拦截恶意超限请求
client_body_buffer_size 只管“放哪暂存”,不管“能不能传”。真正防恶意过载的第一道防线是 client_max_body_size——它在读取请求体前就判断,超限直接返回 413,完全不进缓冲逻辑。
- 对普通表单接口(如登录、注册),设
client_max_body_size 2m;明显超过该值的请求,大概率是扫描器或构造攻击 - 必须与
client_body_buffer_size同作用域(推荐放在location /form/块内),且前者 ≥ 后者,否则合法大表单也会被误拦 - 同步配置后端框架限制(如 Express 的
limit: '2mb'、Spring Boot 的spring.servlet.context-parameters.max-http-post-size),形成前后端双校验
配合 timeout 和 temp path 控制慢速攻击与落盘路径
即使缓冲区设得合理,攻击者仍可用极慢速分段上传长期霸占 buffer 和临时文件句柄。需用配套参数主动收口:
-
client_body_timeout设为 15–30 秒:比默认 60 秒更严,防弱网伪装下的恶意停顿 -
client_body_temp_path /dev/shm/nginx-body 1 2:挂载到内存盘(tmpfs),避免落盘时拖垮磁盘 I/O -
client_body_in_file_only off(默认值):禁用强制落盘;若设为on,所有请求体都写文件,调优失效
验证是否真走内存,别信配置信日志
配置 reload 成功 ≠ 生效。需观测运行态行为:
- 开启 debug 日志:
error_log /var/log/nginx/debug.log debug; - 上传后搜索关键词:
"http client request body buffered"(走内存)或"temp file"(落盘) - 检查临时目录下文件数是否无变化;用
strace -p $(pgrep nginx) -e trace=openat,write确认是否调用临时路径 - 监控 worker 进程 RSS 内存波动,避免因设过大导致持续攀升甚至 OOM


















