一聚教程网:一个值得你收藏的教程网站

热门教程

Nginx 中浏览器缓存如何配合 ETag 和 Last-Modified 实现协商缓存验证

时间:2026-08-27 11:29:48 编辑:袖梨 来源:一聚教程网

协商缓存核心是浏览器“先问再用”,Nginx自动基于文件系统生成Last-Modified和(启用etag on后)弱ETag,响应条件请求返回304;两者分工协作:仅If-Modified-Since时比对时间戳,仅If-None-Match时比对ETag,两者俱全则优先校验ETag。

协商缓存的核心是让浏览器“先问再用”:每次请求前,带着上次拿到的标识去服务端验证是否还能继续用本地副本。Nginx 本身不写业务逻辑,但它能自动基于文件系统信息生成 Last-Modified 和(启用后)ETag,并响应条件请求返回 304 Not Modified —— 整个过程无需前端代码干预,全靠响应头和 Nginx 配置配合。

ETag 和 Last-Modified 各自起什么作用

Last-Modified 是资源最后修改时间(精度为秒),由 Nginx 对静态文件自动设置;ETag 是资源唯一标识(如 W/"12345-67890"),默认不开启,需显式配置 etag on 才会基于文件大小和修改时间生成弱 ETag。

两者不是叠加增强,而是分工协作:

  1. 客户端只发 If-Modified-Since → Nginx 只比对 Last-Modified
  2. 客户端只发 If-None-Match → Nginx 只比对 ETag
  3. 两个请求头都带 → Nginx 优先校验 ETag,命中即返回 304,不再查时间戳

Nginx 配置的关键点

默认行为已支持基础协商缓存,但要稳定生效,建议明确配置以下几项:

  1. location 块中添加 etag on; —— 启用 ETag 自动生成(尤其适合构建产物含 hash、或内容可能更新但 mtime 不变的场景)
  2. 保留 if_modified_since exact;(Nginx 默认值),确保时间比对严格精确
  3. 搭配 add_header Cache-Control "public, max-age=0, must-revalidate"; —— 明确告诉浏览器“缓存立即过期,但必须先验证”,从而触发条件请求
  4. 避免手动用 add_header ETag,否则与 etag on 冲突;也不建议对纯静态资源(如图片、字体)强行加 ETag,徒增 inode 查询开销

为什么有些请求没走 304?常见原因

协商缓存失效往往不是 Nginx 没配好,而是链路中某个环节打断了验证流程:

  1. 后端接口未返回 Last-Modified 头 → Nginx 的 etag on 就不会生效(它依赖该头派生 ETag)
  2. 响应中存在 Set-CookieVary: * → Nginx 默认跳过缓存逻辑,包括协商验证
  3. 前端设置了 Cache-Control: no-cache 但没配 must-revalidate → 浏览器可能忽略验证意图,行为不一致
  4. JS/CSS 文件名带哈希(如 app.a1b2c3.js)→ 这类资源更适合强缓存(immutable + max-age=31536000),禁用协商缓存反而更高效

怎么确认协商缓存真的在工作

不用猜,直接用命令验证:

  1. 首次请求:curl -I https://yoursite.com/static/app.js,检查响应头是否含 Last-Modified 和/或 ETag
  2. 第二次请求:curl -I -H "If-None-Match: "xxx"" -H "If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT" https://yoursite.com/static/app.js,看是否返回 304 且无 Content-Length
  3. 浏览器开发者工具 Network 标签页中,刷新 JS 文件,状态码显示灰色 304、Size 显示 from disk cachefrom memory cache 即表示成功

热门栏目