etag 是 nginx 实现 http 缓存验证的核心机制,配合 if-none-match/if-match 协商资源是否未变;强 etag(如"xxx")要求字节级一致,nginx 默认为静态文件生成;弱 etag(如w/"xxx")表示语义等价,需手动配置或上游注入。

Etag 是 Nginx 中实现 HTTP 缓存验证的核心机制,它不直接决定是否缓存,而是配合 If-None-Match 和 If-Match 请求头,让客户端和服务器协商资源是否“未变”——从而避免重复传输。
强 ETag:字节级一致才通过校验
强 ETag(以 "xxx" 形式表示,无前缀)要求资源内容的每一个字节完全相同。Nginx 默认为静态文件生成强 ETag(基于文件最后修改时间与大小组合的哈希值,如 "5d8a0e9f-2a4b")。当客户端发起带 If-None-Match: "xxx" 的请求时,Nginx 会重新计算当前资源的 ETag 并严格比对:
- 匹配成功 → 返回
304 Not Modified,不发响应体 - 任意字节变化(哪怕改一个空格)→ ETag 不同,返回
200 OK和新内容 - 若响应中含
Cache-Control: no-cache或Pragma: no-cache,浏览器仍会发条件请求,强 ETag 依然生效
弱 ETag:语义等价即可通过校验
弱 ETag 以 W/"xxx" 开头(例如 W/"abc123"),表示“内容在语义上等价”,不要求字节完全一致。Nginx 本身 不原生生成弱 ETag,需手动配置或由上游应用(如 FastCGI、proxy_pass 后端)注入。常见适用场景:
- HTML 页面经服务端动态渲染,但主体内容未变,仅时间戳/统计代码微调
- API 响应中包含非关键字段(如
"updated_at": "2024-06-01T12:00:00Z"随每次请求更新,但业务数据未变 - 使用
add_header ETag W/"$upstream_http_etag";转发后端弱 ETag,同时确保if_modified_since off;避免与 Last-Modified 冲突
Nginx 中控制 ETag 行为的关键配置
Etag 功能默认开启,但行为受多个指令影响,需协同调整:
-
etag on | off;:全局开关,off会彻底移除 ETag 响应头(包括后端传来的) -
if_modified_since before | exact | off;:影响If-Modified-Since校验逻辑;设为off可避免与弱 ETag 混用时的校验冲突 - 静态文件 ETag 无法自定义算法,但可通过
add_header ETag "";清空并替换为自定义值(注意:需配合expires或cache_control确保缓存策略合理) - 代理场景下,若上游已设 ETag,Nginx 默认透传;如需强制重算,需关闭
etag off;并自行添加
调试与验证 ETag 是否生效
实际部署中需确认 ETag 是否按预期工作,推荐组合验证方式:
- 用
curl -I查看响应头是否存在ETag,并观察是否带W/前缀 - 发起两次请求:首次记录 ETag 值,第二次加请求头
-H "If-None-Match: \"xxx\"",检查返回码是否为304 - 修改文件内容后重复测试,强 ETag 应触发
200;若仍返回304,说明 ETag 未更新或被缓存中间件覆盖 - 注意浏览器开发者工具 Network 面板中,
Size列显示from disk cache或from memory cache表示本地缓存命中,而304表示协商缓存生效










