Nginx响应截断主因是响应在抵达缓存逻辑前已被缓冲区截断或非法Header污染,需先通过curl比对、tcpdump抓包和$upstream_http_content_length日志确认截断存在,再据错误日志区分响应头(upstream sent too big header→调大proxy_buffer_size)或响应体(查proxy_buffers、磁盘缓冲)问题,并检查Header合法性及gzip_static配置。

排查 Nginx 代理缓存中响应数据被截断,关键不是看缓存是否命中,而是确认响应在抵达缓存逻辑前是否已损坏或不完整。截断往往发生在缓冲区环节,而非缓存本身——缓存只忠实地存下它收到的内容,若内容本身已被截断,缓存就变成“错的源头”。必须分两步:先验证响应是否真被截断,再判断是响应头还是响应体出问题。
一、确认是否真的发生截断
别依赖浏览器表现或日志有无报错,要实测比对:
- 用 curl -i http://your-api/ | wc -c 获取 Nginx 返回的总字节数;再直连后端(如 curl -i http://backend:8080/ | wc -c),两者明显不等且 Nginx 结果偏小 → 存在截断
- 在 log_format 中加入 $upstream_http_content_length 字段,对比该值与实际返回长度:差值就是被截掉的字节数
- 执行 tcpdump -i lo port 80 -w dump.pcap 抓包,用 Wireshark 打开,观察 Nginx 发给客户端的 TCP payload 是否卡在 4K、32K、64K 等整数边界 —— 这是缓冲区硬限制的典型痕迹
二、区分是响应头还是响应体被截断
错误日志和响应特征能快速定性:
- 错误日志出现 upstream sent too big header → 响应头超限,问题在 proxy_buffer_size
- 日志无报错,但响应体缺失(如 JSON 缺字段、HTML 白屏、CSV 少行)→ 响应体被截,重点查 proxy_buffers 和磁盘临时缓冲
- 用 curl -v http://your-api/ 2>&1 | grep '^ 查看响应头原始输出,若头末尾紧接乱码或异常十六进制(如 0a 0d 0a 0d 后突然中断),说明头解析失败,可能是非法字符导致缓存逻辑跳过
三、检查响应头是否非法,干扰缓存解析
非法 Header(含空格、\r\n、\u00A0、空值如 Cache-Control:)会让 Nginx 拒绝整套响应头解析,$upstream_cache_status 永远不会出现 HIT,缓存无法建立:
- 加调试日志:log_format debug_log '$remote_addr "$request" $status $upstream_http_cache_control $upstream_http_etag';,观察 $upstream_http_cache_control 是否为空或含不可见字符
- 临时绕过:在 location 中加 proxy_ignore_headers Cache-Control Expires ETag;,并配合 proxy_cache_valid 200 10m; 强制缓存(仅用于验证,非长期方案)
- 根治方式:修复后端返回的 Header,确保所有字段值合法、无多余空白、无控制字符
四、验证缓存内容是否真正完整
即使缓存命中,也可能存的是半截响应:
- 对静态资源(如 .js.gz),比对 curl -s http://your-domain/file.js | wc -c 与磁盘上对应 .gz 文件大小,不等即被截断
- 确认 gzip_static on; 已启用,且 .gz 文件存在、Nginx 用户有读权限
- 若使用 proxy_cache,检查 proxy_max_temp_file_size 是否为 0 —— 为 0 会禁用磁盘缓冲,超内存直接丢弃后续数据;建议设为 1024m 并确保 proxy_temp_path 所在磁盘空间充足、权限正确(常见故障:目录属主为 nobody,但 worker 进程以 www-data 运行)


















