要让Nginx正确支持静态资源304缓存协商,需确保响应含Last-Modified或ETag头,且Cache-Control设为no-cache或must-revalidate,并将相关配置置于实际生效的location块中。

要让 Nginx 正确支持静态资源的 304 缓存协商,关键不是单纯加头,而是让浏览器能发起 If-Modified-Since 或 If-None-Match 请求,并让 Nginx 有依据返回 304。这依赖于服务端提供 Last-Modified 和/或 ETag,且配置不被更高优先级 location 覆盖。
确保响应头包含 Last-Modified 或 ETag
Nginx 默认对静态文件(如通过 root 或 alias 提供的 .js、.css、图片)会自动设置 Last-Modified 头(基于文件修改时间)。但若你用 add_header 覆盖了它,或用了 proxy_pass 代理静态服务,就可能丢失。确认方式:访问一个 JS 文件,检查响应头是否含 Last-Modified。
- 不要在 location 中写
add_header Last-Modified ""或清空它 - 避免用
expires off同时又删掉Last-Modified,否则协商缓存失效 - 如需强制启用 ETag(默认已开启),可加
etag on;,无需额外配置
用 expires + Cache-Control 控制协商行为
expires 指令不仅设 Expires 头,还会生成 Cache-Control: max-age=xxx。但若你想让浏览器“每次都校验”,应避免设长缓存,改用 no-cache 或 must-revalidate:
-
expires 1h;→ 浏览器 1 小时内不发请求,自然不会触发 304 -
add_header Cache-Control "no-cache";→ 浏览器每次发请求,带If-Modified-Since,Nginx 可比对后返回 304 -
add_header Cache-Control "public, must-revalidate, max-age=0";效果类似,兼容性更广
location 匹配顺序决定 304 是否生效
如果一个请求同时匹配多个 location,Nginx 会按优先级选一个执行。若高优先级的 location(如 ^~ /static/)没配缓存头,而低优先级的正则 location(如 ~* \.(js|css)$)配了,后者根本不会执行。
- 把
add_header Cache-Control和expires放进实际生效的 location 块里,比如location ^~ /static/ { ... } - 避免在
location /下全局设缓存,否则 HTML 也可能被缓存,影响首屏更新 - 测试方法:curl -I http://your-domain/static/app.js,看响应头是否含
Last-Modified和你设定的Cache-Control
验证 304 是否真实返回
浏览器是否发条件请求、Nginx 是否返回 304,取决于客户端行为和服务器响应头组合。简单验证步骤:
- 首次访问资源,记录响应状态码(200)和
Last-Modified值 - 刷新页面,打开开发者工具 → Network → 找该资源,看 Status 是 200 还是 304
- 若始终 200,检查是否禁用了浏览器缓存(DevTools 中勾选了 “Disable cache”)
- 若始终 304,说明缓存策略太激进,可适当延长
max-age减少校验频率


















