应停用 if_modified_since 并启用基于内容哈希的强 ETag:确保 etag on、无手动覆盖 ETag 头、Nginx ≥1.19.8、各节点文件内容与路径一致,并配合 long-term Cache-Control 减少协商请求。

要解决 Nginx 在多节点集群中 If-Modified-Since 与 ETag 的校验冲突,核心是避免依赖文件系统时间戳(mtime)——因为各服务器上同一文件的修改时间很可能不一致,导致协商缓存行为不可靠。
停用 mtime 依赖,改用内容哈希型 ETag
Nginx 1.19.8+ 默认对静态文件使用强 ETag(基于文件内容 SHA 哈希),但前提是文件内容和路径在所有节点完全一致。若构建产物已统一分发,只需确认:
- etag on; 已启用(默认即开启)
- 未配置
add_header ETag或more_set_headers "ETag:",否则会覆盖 Nginx 自动计算值 - 所有节点使用相同版本的 Nginx(建议 ≥1.19.8),且未禁用
open_file_cache导致内容未重读
关闭 If-Modified-Since 校验逻辑
即使 ETag 正常,若同时开启 if_modified_since,Nginx 在收到同时带 If-None-Match 和 If-Modified-Since 的请求时,仍会按 RFC 优先匹配 ETag;但部分客户端或中间件可能只发 If-Modified-Since,此时 mtime 不一致就会触发错误 200。稳妥做法是:
- 在 server 或 location 块中设 if_modified_since off;
- 配合 expires 或 Cache-Control 设置长期缓存(如
max-age=31536000),让浏览器主要走强缓存,减少协商请求频次
统一后端生成或强制覆盖 ETag(无升级条件时)
若集群节点 Nginx 版本较低(
- 后端(如 Node.js/Python)在响应静态资源时,计算文件内容 SHA256 并写入 ETag: "abc123..."(不带
W/前缀为强验证) - 在 Nginx 负载均衡层,用 proxy_hide_header ETag; 清除上游可能误传的旧 ETag,再用 add_header ETag "$upstream_http_etag"; 透传可信值
- 若完全无法控制后端,可退而求其次:对构建产物固定弱 ETag,例如 add_header ETag "W/\"v2.3.1\"";,并确保该版本号随发布严格更新
验证是否生效的三步检查法
部署后必须实测,不能仅看配置:
- 用 curl -I https://site.com/app.js 确认响应头含
ETag: "xxx"且无W/(强 ETag) - 修改文件内容 → 重新部署 → 再次请求,ETag 值必须变化;不变说明仍走 mtime 或被缓存干扰(临时加
open_file_cache off;排查) - 手动发起带头请求:curl -H "If-None-Match: \"xxx\"" -I https://site.com/app.js,应返回
304;改用错误值则返回200











