Cache-Control 设置了 max-age=3600,为什么浏览器还是发请求?

UX玉萱 阅读 15

我给静态资源加了 Cache-Control: max-age=3600,但每次刷新页面,浏览器还是会向服务器发请求,只是返回 304。不是应该直接用缓存、不发请求才对吗?

我试过在 Nginx 里配置:

location ~* .(js|css|png|jpg)$ {
    expires 1h;
    add_header Cache-Control "public, max-age=3600";
}

但 Chrome DevTools 的 Network 面板里,每次刷新都看到请求发出,状态是 304 Not Modified。这算没生效吗?

我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
慕容蓝月
这个问题的关键在于浏览器刷新行为的特殊性。当你手动刷新页面(按F5或刷新按钮),大多数浏览器会默认带上 Cache-Control: max-age=0 的请求头,强制检查资源是否有更新。

304状态码其实说明缓存机制是生效的 - 服务器确认资源没变,所以没有返回完整内容。但这不是最优状态,我们想要的是完全不发请求(直接从内存/磁盘读取)。

要解决这个问题,需要两方面的调整:

1. 确保服务器正确配置缓存头:
location ~* .(js|css|png|jpg)$ {
# 设置过期时间(同时会生成对应的Cache-Control)
expires 1h;

# 确保ETag被移除(避免304检查)
etag off;

# 更完整的Cache-Control设置
add_header Cache-Control "public, max-age=3600, immutable";
}


2. 理解不同刷新方式的区别:
- 普通刷新(F5):会发送条件请求(可能返回304)
- 强制刷新(Ctrl+F5):完全忽略缓存,返回200
- 地址栏回车/正常导航:会优先使用缓存

我建议你测试时用地址栏回车而不是刷新按钮,这样更接近真实用户行为。另外加上 immutable 参数可以告诉浏览器:在max-age期间资源永远不会变,连条件请求都不用发。

补充一个冷知识:Chrome在开发者工具打开时,默认行为会更倾向于发送请求验证缓存,这是为了方便调试。你可以:
1. 关闭DevTools再测试
2. 或者右键刷新按钮选择"正常重新加载"

最后提醒下,ETag和Last-Modified这类验证机制会和强缓存产生冲突。既然我们用了max-age,最好直接禁用ETag,就像上面配置那样。
点赞 1
2026-03-05 11:05