Nginx“不完整的响应”主因是后端非法Header阻断缓存解析或缓冲区过小导致响应体截断;需通过curl+xxd查异常字节、$upstream_http_cache_control日志定位Header问题,调大proxy_buffer_size/proxy_buffers或关proxy_buffering解决截断,并统一Vary与cache_key防碎片化。

Nginx 缓存配置中出现“不完整的响应”,通常不是缓存本身失效,而是响应在抵达 Nginx 缓存逻辑前就被截断或污染——导致缓存无法提取关键头(如 Cache-Control)、无法写入缓存体,甚至直接返回空/乱码内容。核心问题集中在两个层面:一是后端响应头非法,阻断缓存解析;二是响应体被缓冲机制截断,缓存只存了半截数据。
检查响应头是否非法,避免缓存逻辑瘫痪
当后端返回含空格、控制字符(如 \u00A0、\r\n)、空值(如 Cache-Control: max-age=)的 Header 时,Nginx 会拒绝解析整套响应头,$upstream_cache_status 永远不会出现 HIT 或 STALE,日志中高频报 upstream sent invalid header。
- 用
curl -v http://your-domain/查看原始响应头后是否紧接异常字节,配合xxd看十六进制流 - 在对应
location中加调试日志:log_format cache_debug '$remote_addr "$request" $status $upstream_http_cache_control';,观察$upstream_http_cache_control是否为空或含\x20 - 临时缓解:加
proxy_ignore_headers Cache-Control Expires,让 Nginx 忽略非法头,改用proxy_cache_valid强制生效(仅兜底,非根治)
验证响应体是否被截断,确保缓存内容完整
即使响应头合法,若 gzip 静态文件缺失、代理缓冲区过小或 proxy_buffering 触发提前终止,Nginx 可能只缓存并返回部分字节——浏览器解压失败、页面白屏、内容缺失,但 Nginx 日志无错误。
- 对比真实
.gz文件大小与curl -s URL | wc -c结果,不等即被截断 - 确认
gzip_static on已在对应location块启用,且.gz文件存在、权限可读 - 增大缓冲能力:
proxy_buffer_size 128k; proxy_buffers 8 256k; proxy_busy_buffers_size 512k; - 对超大响应或流式接口,可关缓冲:
proxy_buffering off;(慎用,影响并发性能)
统一 Vary 与缓存键,防止缓存碎片化干扰完整性判断
如果 Vary 头滥用(如盲目 Vary: User-Agent),会导致同一 URL 被拆成成百上千个缓存副本,部分副本因未命中而穿透回源——此时你看到的“不完整响应”,其实是不同设备请求混用了不匹配的缓存体。
- 只对真正影响响应内容的请求头做
Vary,例如后端按Accept-Language返回不同文案才加 - 用
map归一化不稳定头:map $http_user_agent $device { ~*mobile "mobile"; default "desktop"; } - 确保
proxy_cache_key与add_header Vary同步包含该归一化变量,例如:proxy_cache_key "$host$request_uri$device"; add_header Vary "X-Device";
配置后必须验证缓存行为本身
别只盯响应头有没有 X-Cache: HIT,要实测缓存是否真正“存对了、取全了”:
- 用相同请求头连续发起两次请求,检查第二次响应体字节数、MD5 与第一次是否完全一致
- 修改一个不影响缓存键的请求头(如
X-Debug: 1),确认仍命中缓存(排除误加Vary) - 清空本地浏览器缓存,用
curl -H "Cache-Control: no-cache"强制回源,再比对响应是否与缓存版本一致


















