在 Nginx 中:
请求头:在 rewrite / access 阶段就已解析
请求体(body):
只有在“模块明确读取 body”时才会被加载到内存
而你当前的 location /notify:
属于 rewrite 阶段直接结束请求,此时:
Nginx 不会去读 request body
body 数据还在 socket 里
$request_body 根本还不存在
这是设计行为,不是 bug
Nginx 的处理顺序简化如下:
关键点:
return 不会触发 request body 读取
access_log 只能记录“已经解析过的变量”
$request_body 未被加载 → 为空字符串
你这里:
如果启用 echo_read_request_body,body 就能读出来
这不是巧合,而是因为:
echo_read_request_body 强制触发了请求体读取
你用的 curl 请求是完全正确的:
这点要强调:
❌ 是否 POST —— 无关
❌ 是否 JSON —— 无关
❌ 是否有 Content-Length —— 无关
✅ 是否有模块“消费 request body”—— 决定性因素
很多人会疑惑:
“我 proxy_pass 的时候,$request_body 有时是有的?”
原因是:
proxy_pass 会读取 body 并转发给 upstream
读取动作发生 → $request_body 被填充
access_log 才能记录
而你现在是 纯 return 场景。
下面是可选方案,从推荐到不推荐。
最干净、可控、生产可用
location /notify {
content_by_lua_block {
ngx.req.read_body()
local body = ngx.req.get_body_data()
ngx.log(ngx.INFO, "request body: ", body)
ngx.header["Content-Type"] = "application/json"
ngx.say('{"code":0,"msg":"接收成功"}')
}
}
优点:
明确读取 body
不污染 access_log
可做签名校验、JSON 解析、限流等
支付宝 / 微信 / 回调场景最常用
强制让 Nginx 读 body:
location /notify {
client_max_body_size 1m;
client_body_buffer_size 1m;
client_body_in_single_buffer on;
proxy_pass http://127.0.0.1:65535; # 黑洞 upstream
}
配一个“假 upstream”,只为触发 body 读取。
缺点:非语义化,增加一次无意义的 proxy,调试成本高
location /notify {
echo_read_request_body;
access_log /usr/local/nginx/logs/notify_body.log access;
return 200 '{"code":0,"msg":"接收成功"}'; }
说明:
echo 模块不是官方模块
不建议生产环境长期使用
但用于验证问题非常合适
因为 Nginx 的设计哲学是:
“不要为你没用到的东西付出性能成本”
请求体可能是:几 KB,几百 MB
chunked stream
所以:默认不读取,只有模块明确需要时才读
你在 location 中使用 return 直接结束请求,
Nginx 从未读取 request body,
因此 $request_body 在 access_log 中永远是空的。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!