nginx 默认无法在 access_log 中记录 json 响应体,因其不支持 $response_body 变量,强行实现会引发性能、安全与完整性问题;推荐由后端应用自行打点关键字段,nginx 仅记录请求元信息和响应头中轻量级自定义字段。

默认情况下,Nginx 的 access_log 不会记录响应体(比如 JSON 返回内容),因为响应体属于后端应用生成的数据,Nginx 本身不解析或缓存它。直接在 access_log 中记录完整 JSON 响应体不仅不可靠,还可能带来性能、安全和隐私风险。
为什么不能直接用 access_log 记录 JSON 响应体
Nginx 的日志模块只支持记录变量(如 $status、$request_time、$upstream_http_content_type 等),而响应体($response_body)**不是内置变量**,也不被标准模块支持。试图通过第三方模块(如 nginx-http-log-response-body)强行记录,会面临以下问题:
- 需重新编译 Nginx 或启用非官方模块,运维成本高
- 记录响应体可能导致日志暴增(尤其大 JSON 或高频接口)
- 敏感数据(如 token、手机号、身份证)意外落盘,违反安全规范
- 响应体未完全缓冲时(如流式响应),记录内容不完整或乱码
推荐的替代方案:由上游应用控制日志输出
最合理、可控、可审计的方式是:让后端服务(如 Python/Java/Node.js)在返回 JSON 前,自行将关键字段(如 status、code、message、耗时)打点到统一日志系统(如 ELK、Loki、Filebeat 收集的本地文件)。Nginx 只负责记录请求元信息:
- 客户端 IP(
$remote_addr)、时间($time_iso8601) - 请求路径与参数(
$request_uri)、方法($request_method) - 上游状态(
$upstream_status)、耗时($upstream_response_time) - 响应头关键字段(如
$upstream_http_x_request_id)用于链路追踪
这样既满足可观测性,又规避了 Nginx 层处理响应体的缺陷。
如果必须在 Nginx 层记录部分响应信息(谨慎使用)
仅限调试场景,且只提取响应头中已有的、轻量级字段(如自定义 header):
- 后端在返回 JSON 时,同时设置一个响应头:
X-Api-Result: success或X-Api-Code: 20000 - Nginx 配置中定义日志格式,引用该 header:
log_format api_json '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'$upstream_response_time "$http_user_agent" '
'"$upstream_http_x_api_code" "$upstream_http_x_api_result"';然后在 server 或 location 块中启用:access_log /var/log/nginx/api.log api_json;
绝对不要做的操作
以下方式看似“能用”,实则危险或无效:
- 尝试用
$echo_response_body(需 echo 模块,且仅支持 echo 指令内部,不适用于 proxy_pass) - 用 Lua +
ngx.arg[2]在log_by_lua中读取响应体 —— 此时响应可能已被释放,读到空或截断内容 - 开启
proxy_buffering off并配合 body_filter_by_lua —— 极易导致超时、内存泄漏、日志错位











