Nginx 实现 ETag 协商缓存的核心是透传后端 ETag、确保客户端携带 If-None-Match、并配置 Cache-Control: public, max-age=0, must-revalidate 以强制验证;需后端稳定输出语义准确的 ETag 或 Last-Modified,Nginx 显式启用 etag on 且不干扰响应头,三者协同方可生效。

要在 Nginx 中通过 ETag 实现高效的浏览器协商缓存校验,核心不是让 Nginx “计算”或“校验” ETag,而是确保它正确透传、保留并复用后端生成的 ETag,同时让客户端按规范发起条件请求。整个机制依赖三方协同:后端稳定输出语义准确的 ETag、Nginx 不破坏协商链路、浏览器主动携带 If-None-Match。
确认后端已输出合法 ETag 或 Last-Modified
Nginx 的 etag on 仅对静态文件或带 Last-Modified 响应头的代理响应生效;若后端 API(如 /api/user)未返回该头,Nginx 不会自动补 ETag。必须先验证真实响应:
- 用
curl -I https://your.domain/api/data检查响应头中是否存在ETag(推荐强 ETag:"abc123")或Last-Modified - 若缺失,需在后端添加:Express 中用
res.set('Last-Modified', new Date().toUTCString());FastAPI 中通过Response(headers={"ETag": '"d41d8cd98f00b204e9800998ecf8427e"'})显式设置内容哈希值 - 避免后端设了 ETag 又在 Nginx 开
etag on,可能引发冲突;二者选其一即可
在 Nginx 中启用并保护 ETag 传递
对于静态资源(.js/.css/.png),默认 etag on 已开启,基于文件大小+修改时间生成弱 ETag,基本可用。代理动态接口时,重点是不干扰已有 ETag:
在 Linux 上通过 Chrome 挂载/VNC 自动发布小红书长笔记。Agent 撰写标题和正文后执行 xhs_publish.sh --publish --submit,触发小红书发布。
- 在对应
location块中明确写etag on;(默认为 off,需显式开启) - 禁用可能覆盖或清除 ETag 的指令,例如不要写
etag off;或add_header ETag ""; - 若后端已返回 ETag,Nginx 默认透传;如需强制使用后端 ETag(尤其弱 ETag 场景),可加
add_header ETag $upstream_http_etag;并配if_modified_since off;避免与 Last-Modified 冲突 - 确保不忽略关键响应头:
proxy_ignore_headers Set-Cookie Vary;(若接口无用户态,否则 Nginx 默认跳过缓存)
配置 Cache-Control 明确启用协商缓存
浏览器是否发 If-None-Match,取决于本地是否有 ETag 缓存 + 是否过了强缓存期。要强制走协商流程,需禁用强缓存:
- 设置
add_header Cache-Control "public, max-age=0, must-revalidate"; - 避免使用
no-cache以外的强缓存指令(如max-age=3600),否则浏览器可能直接读本地缓存而不发条件请求 - 切勿设
no-store或private(除非业务要求),它们会阻止 ETag 协商生效
验证协商缓存是否真正生效
仅看响应头有 ETag 不代表协商成功,需观察完整请求-响应闭环:
- 首次请求:状态码 200,响应头含
ETag: "xxx"和Cache-Control: ... must-revalidate - 第二次请求:用
curl -H "If-None-Match: \"xxx\"" https://...,应返回 304 Not Modified,且响应体为空(Content-Length 缺失或为 0) - 浏览器 DevTools → Network → 查看 Request Headers 是否含
If-None-Match,Response Headers 是否为 304 - 若返回 200 且带新 ETag,检查后端是否每次返回不同值(如用时间戳生成)、或 Nginx 是否因
Set-Cookie跳过缓存

















