为什么设置了Cache-Control但浏览器还是重新请求资源?

晴文 Dev 阅读 60

我正在优化网站静态资源加载,按照教程设置了Cache-Control: public, max-age=3600,但发现每次刷新页面时资源都会重新请求。用开发者工具看响应头确实有这个字段,但网络标签显示状态是200(from network)而不是304。难道还有其他设置没考虑到?

尝试过以下配置:
在服务器响应头里添加了:


{
  "Cache-Control": "public, max-age=3600",
  "ETag": "abc123"
}

但浏览器控制台显示每次请求都带着If-None-Match,服务器返回的是新内容而不是304。难道max-age和ETag配合有问题吗?

我来解答 赞 4 收藏
二维码
手机扫码查看
2 条解答
皇甫嘉倪
你这个情况其实很常见,问题出在 Cache-Control 虽然设置了 max-age=3600,但浏览器在刷新页面时的行为和正常导航不一样。

根据 HTTP 规范和 MDN 文档里的说明,当用户手动刷新页面(比如按 F5 或点击刷新按钮)时,浏览器会强制跳过强缓存,即使资源还在 max-age 有效期内,也会重新发起请求验证。这就是为什么你看到状态是 200 from network 而不是 from memory cache 或者 304。

只有在普通前进后退、或者页面内链接跳转这种非刷新场景下,max-age 才会生效,直接使用缓存而不发请求。

另外你说服务器每次都返回新内容而不是 304,这说明服务端没有正确处理 If-None-Match。虽然你设置了 ETag: abc123,但如果每次响应的 ETag 实际上都在变,那校验就会失败,导致返回 200。你需要确保同一个资源的 ETag 是稳定的,只有内容变了才更新它。

还有一个点是,max-age 和 ETag 并不冲突,它们是可以配合使用的。max-age 控制强缓存有效期,过了这个时间才会发起条件请求,带着 If-None-Match 去验证。但在刷新时,浏览器会提前绕过强缓存,直接发起带验证头的请求。

所以结论是:

如果你看到的是刷新页面时的请求行为,这是正常的,别被迷惑了。你应该测试的是:打开页面 -> 关掉标签页 -> 重新进入网站 -> 看静态资源是否走缓存。

可以用 performance.navigation.type 区分是首次加载还是刷新。也可以在开发者工具里看 Size 列:如果是 from memory cache 或 disk cache,就不会有网络请求;如果显示 200 but from disk cache,其实是命中了强缓存。

真正要验证缓存逻辑,建议用 curl 测试:

curl -H "If-None-Match: abc123" -H "Cache-Control: max-age=0" -I http://yoursite.com/static/file.js


这时候服务器应该返回 304,否则就是 ETag 验证逻辑没做好。

总结一下:max-age 没问题,但刷新行为会跳过缓存;ETag 必须稳定且服务端要做正确比对才能返回 304。两个机制各司其职,一个管时间,一个管验证。
点赞 5
2026-02-12 11:13
UX世豪
UX世豪 Lv1
你这个配置没问题,但刷新页面时浏览器默认不会使用缓存,会强制发起新请求。要验证缓存是否生效,应该关掉页面再打开,或者用开发者工具清空网络记录,看是不是 304。试试看:

curl -I http://yourdomain.com/yourfile.js


看返回头有没有 HTTP/1.1 304 Not Modified,有说明缓存生效了。浏览器 Network 面板里刷新看到 200 是正常行为。
点赞 9
2026-02-04 12:00