必须禁用Nginx默认ETag(etag off;),改用构建时预计算的内容哈希(如SHA-256)注入为标准ETag头,并同步禁用Last-Modified、统一Cache-Control策略,以确保多节点部署下缓存验证一致。

核心问题不在“编译时间”,而在于 Nginx 默认生成 ETag 时依赖文件的 修改时间(mtime)和大小,在多节点部署中,即使内容完全相同,只要文件被复制、解压或同步时机不同,各节点上文件的 mtime 就会不一致 → 导致 ETag 值不同 → 浏览器携带某台节点返回的 ETag 再次请求时,其他节点无法匹配,缓存验证失败,被迫返回完整响应(200),浪费带宽与服务资源。
停用默认 ETag 生成机制
这是所有方案的前提。Nginx 默认的 etag on; 行为不可控且与文件系统强耦合,必须关闭:
- 在
http、server或location块中显式写入:etag off; - 确保该指令未被子配置覆盖(例如 location 中没意外写回
etag on;) - 重启或重载 Nginx 生效
统一使用构建时预计算的内容哈希作为 ETag
最稳定、可复现、跨节点一致的方案:ETag 值由构建流程(CI/CD)生成,与运行时环境完全解耦。
- 在前端/静态资源构建阶段(如 Webpack、Vite 打包),对每个输出文件计算 SHA-256 或 MD5,并将哈希值写入文件名(如
app.a1b2c3d4.js)或元数据文件(如manifest.json) - 部署时,将哈希值注入 HTTP 响应头 —— 推荐方式是通过自定义 header 透传,例如:
X-Content-Hash: a1b2c3d4... - Nginx 配置中用
add_header ETag "$sent_http_x_content_hash";将其映射为标准 ETag 头(注意:需确保该 header 已由后端或静态服务设置;若纯静态托管,可用 Lua/OpenResty 或外部工具预写入)
若无法修改构建流程,可在 Nginx 层强制设为固定弱 ETag
适用于内容绝对不变的静态资源(如版本化构建产物、CDN 分发前的最终包):
- 用
add_header ETag "W/\"v1.2.3-build20260410\"";硬编码一个语义化版本标识 - 务必配合
Cache-Control: public, max-age=31536000等长效缓存策略 - 每次资源内容变更时,必须同步更新该字符串(否则缓存永远不刷新)
- 不适用于 API 响应或动态内容
同步校验其他缓存关键字段
仅修复 ETag 不够。Last-Modified 同样依赖 mtime,也会因节点间时间差异或文件操作导致不一致:
- 禁用默认 Last-Modified:
expires epoch; add_header Last-Modified "";(清空)或直接用add_header Last-Modified "Wed, 01 Jan 2025 00:00:00 GMT";设为固定可信时间戳 - 确保
Cache-Control在所有节点返回完全一致(如都设为public, immutable或no-cache) - 避免混合使用 ETag 和 Last-Modified 做双重校验,除非二者严格同步


















