nginx对静态资源etag的处理是自动且条件触发的,无etag on/off指令;仅当请求真实本地文件、sendfile开启、未启用gzip/gzip_vary且响应体未被修改时,才基于size和mtime生成弱etag(如w/"1a2b3c-4d5e6f")并参与304协商。

Nginx 对静态资源的 ETag 处理是自动的、条件触发的,**没有 etag on/off 这类配置指令**,也不能手动指定或覆盖其值。它不是靠“开启开关”生效的功能,而是由底层文件服务逻辑在满足特定前提时自动生成并附加到响应头中的。
ETag 生成的前提条件
只有同时满足以下几点,Nginx 才会为静态文件(如 .jpg、.css、.js)添加 ETag 响应头:
- 请求的是真实存在的本地文件(非 proxy_pass、fastcgi 或子请求返回的内容)
- 启用了 sendfile on(默认开启,且对性能关键)
- 未启用 gzip 或 gzip_vary(否则内容编码不稳定,ETag 会被禁用)
- 文件未被第三方模块或 Lua 脚本修改原始响应体
ETag 的实际取值方式
Nginx 默认生成的是弱 ETag(格式为 W/"size-mtime"),由文件大小(size)和最后修改时间(mtime)两个字段拼接后转为十六进制构成,例如:W/"1a2b3c-4d5e6f"。
它不基于文件内容哈希(如 MD5/SHA),因此:
- 相同内容但不同文件名 → ETag 不同,无法复用缓存
- 文件仅改名未改内容 → 浏览器视为全新资源,不发 If-None-Match 请求
- mtime 精度为秒级,1 秒内多次修改 → ETag 可能不变,校验失效
ETag 如何参与缓存协商
当浏览器已缓存某资源,并携带 If-None-Match: "xxx" 发起请求时,Nginx 会:
- 重新计算当前文件的 ETag(同样基于 size + mtime)
- 与请求头中的值做字符串比对(区分强/弱校验)
- 匹配成功 → 返回 304 Not Modified,不传响应体
- 不匹配 → 返回 200 OK 和新内容
注意:若响应中已有 Cache-Control: public, max-age=31536000,浏览器通常直接复用本地副本,根本不会发起条件请求——此时 ETag 完全不生效。
内容哈希型 ETag 的例外情况
从 Nginx 1.17.5 起,若启用 etag on; 且配合 open_file_cache 正确使用,部分构建可支持基于文件内容生成强 ETag(如 "abc123def456...")。但这需要:
- 明确升级到 1.18.0+ 稳定版
- 确保未用
add_header ETag覆盖原值 - 避免与
if_modified_since混用导致逻辑冲突 - 通过
curl -I实际验证 ETag 是否随内容变化而变化











