强缓存
强缓存不走服务器,浏览器直接使用本地缓存。
Cache-Control
Cache-Control: public, max-age=3600
常用指令:
max-age=<seconds>:缓存有效期(秒)public:可被 CDN、代理服务器、浏览器缓存private:只能被浏览器缓存no-cache:不直接使用缓存,每次都要和服务器验证no-store:完全不缓存
Expires
Expires: Wed, 21 Oct 2025 07:28:00 GMT
HTTP/1.0 的产物,已过时,通常和 Cache-Control 同时使用作为向后兼容。
协商缓存
强缓存过期后,浏览器发起请求,服务器决定是否使用缓存。
Last-Modified / If-Modified-Since
# 服务器响应
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
# 浏览器下次请求
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT
服务器检查资源是否在 If-Modified-Since 之后有变化:
- 无变化:返回
304 Not Modified - 有变化:返回
200 OK+ 新内容
ETag / If-None-Match
# 服务器响应
ETag: "33a64df551425fcc55e4d42a148795d9"
# 浏览器下次请求
If-None-Match: "33a64df551425fcc55e4d42a148795d9"
ETag 是资源的唯一标识(通常用 hash),比 Last-Modified 更精确。
常见缓存场景
场景一:静态资源长期缓存
# CSS, JS, 图片
Cache-Control: public, max-age=31536000, immutable
# 一年缓存,内容变化时 URL 变化
场景二:HTML 每次验证
Cache-Control: no-cache
ETag: "abc123"
# 每次都要验证,但验证通过后可以用缓存
场景三:用户相关数据不缓存
Cache-Control: no-store, private
# 敏感数据完全不缓存
实际项目配置
Nginx
# 静态资源
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store";
}
Express
app.use('/static', express.static('public', {
maxAge: '1y',
setHeaders: (res, path) => {
if (path.endsWith('.html')) {
res.setHeader('Cache-Control', 'no-cache');
}
}
}));
缓存失效的排查
常见问题
-
强缓存生效但需要更新:内容变了但用户看到旧内容
解决:内容变化时改变 URL(加 hash)
-
协商缓存每次都返回 200:缓存生效但每次都发请求
解决:检查 ETag/Last-Modified 是否正确设置
-
Cache-Control 配置错误:
no-cache和no-store混淆no-cache:每次验证但可以用缓存no-store:完全不缓存
这一章想说的
强缓存和协商缓存的区别:
- 强缓存:不看服务器,直接用本地缓存
- 协商缓存:问服务器资源是否变化
最佳实践:
- 静态资源:强缓存 + 内容版本化
- HTML:协商缓存(no-cache)
- 用户数据:不缓存(no-store)