一张清单解决:如果你只改一个设置:优先改缓存管理的误区(信息量有点大)

导语
缓存配置往往被当作“微优化”,结果一配置不当就把用户体验、部署流程和故障排查都拖垮了。这里给出一个可直接落地的结论 + 完整清单,帮你用最小改动获得最大收益:如果你只能改一个设置,就把 HTTP 缓存策略(Cache-Control + 版本化)做好——静态资源长缓存并可版本化,HTML 页面采用短缓存/可重新验证(conditional requests)。下面告诉你为什么、怎么改、常见误区与排查方法。
核心结论(可直接复制粘贴)
- 静态资源(JS/CSS/图片/字体):Cache-Control: public, max-age=31536000, immutable;使用文件指纹/哈希(例如 app.abc123.js)。
- HTML/接口响应:Cache-Control: no-cache, must-revalidate(或 max-age=0, s-maxage=60 结合 CDN);同时保留 ETag 或 Last-Modified 以支持条件请求(304)。
- 对于共享缓存(CDN、代理),用 s-maxage 控制边缘缓存;origin 用 max-age/ETag 支持客户端短时缓存与条件校验。
这一个组合能避免“用户看不到新内容”又能让静态资源得到长期缓存收益。
为什么把它放在第一位
- 大多数性能问题和部署问题都与缓存策略冲突有关:要么静态资源永远不缓存,要么 HTML 被长时间缓存导致用户拿到旧页面。
- 正确区分“可长期缓存的不可变资源”和“需要频繁更新的可变资源”能立刻提升缓存命中率同时避免缓存失效带来的发布噩梦。
常见误区与纠正
- 误区:把所有东西都设置长缓存。后果:用户拿不到新版本,频繁要靠强制刷新或改文件名才能更新。纠正方法:长期缓存只给“不可变且版本化”的资源。
- 误区:把 HTML 设为 no-store/no-cache 完全禁止缓存。后果:降低 CDN/代理优化能力,增加带宽。纠正方法:让 HTML 可被条件校验(ETag + no-cache)或在 CDN 设置短 s-maxage。
- 误区:以为 CDN 自动解决一切。CDN 受原始响应头影响,且需要正确配置缓存键、变体(Vary)和清除策略。
- 误区:使用查询字符串作为版本控制(例如 ?v=1.2)。部分 CDN/代理默认不把有查询字符串的 URL 长缓存,或被认为是动态请求。优先用文件指纹在路径内。
一张清单(逐项可执行)
配置前准备
- 确定哪些资源是“不可变”(只会通过文件名变更)vs “可变”(HTML、API 响应)。
- 确保构建流程支持文件指纹(hash in filename)。
静态资源(JS/CSS/图片/字体)
- 设置响应头:Cache-Control: public, max-age=31536000, immutable
- 生成文件指纹并把引用更新到页面(例如 app.abc123.js)
- 在 CDN 上启用长时间缓存并确认缓存键包含文件名路径
- 若文件大小敏感,开启 gzip 或 brotli 压缩及正确的 Content-Encoding
HTML 与 API(动态/可变内容)
- 设置响应头:Cache-Control: no-cache, must-revalidate(或 max-age=0, s-maxage=60)
- 保留 ETag 或 Last-Modified,用于条件 GET(服务端返回 304)
- 对于公共 API 考虑使用 s-maxage 来允许边缘缓存而原点保留短期控制
- 如果页面有用户敏感内容,使用 Cache-Control: private
CDN 与边缘缓存
- 确定缓存优先级:edge(s-maxage)优于 origin(max-age)
- 配置缓存清除(purge)或按文件名版本化,避免依赖手动清除
- 配置缓存键:是否包含查询字符串、Cookie、Authorization、Accept-Language 等
- 对需要即时生效的资源不依赖 purge,优先用版本化替换 URL
Service Worker(如果使用)
- Service Worker 的缓存策略独立于 HTTP 缓存,保证策略一致:静态由 SW 管控且使用版本化;HTML 委托浏览器+服务器处理或采用网络优先+更新提示
安全与变体(Vary)
- 对压缩变体确保设置 Vary: Accept-Encoding
- 若根据用户语言或设备返回不同内容,谨慎添加 Vary(会增加缓存碎片)
开发与发布流程
- 开发环境:可用短缓存或禁用缓存,但确保生产构建使用版本化
- 发布策略:构建产物包含 hash;回滚通过代理指向旧版本或部署旧构建
- CI/CD 在构建后自动上传并记录新版本,减少手工 purge
测试与排查(快速命令)
- 查看响应头:curl -I https://example.com/path
- 强制重新验证:curl -H "If-None-Match: " -i …
- 浏览器检测:打开 DevTools → Network,观察 Size/Status(304 表示条件请求生效)
- CDN 是否命中:看 Header(例如 X-Cache: HIT/MISS 或 CF-Cache-Status)
- 常见问题:If you see old assets after deploy → 检查文件名是否变了、CDN 是否 purge、浏览器是否从 service worker 读取
示例配置片段(直接可用)
- 静态资源:Cache-Control: public, max-age=31536000, immutable
- HTML:Cache-Control: no-cache, must-revalidate
- Nginx(静态与 HTML 区分):
location ~* .(?:css|js|jpg|jpeg|png|gif|svg|woff2?)$ {
addheader Cache-Control "public, max-age=31536000, immutable";
}
location / {
addheader Cache-Control "no-cache, must-revalidate";
}
- Express 简单例子:
app.use('/static', express.static('public', {
maxAge: '1y', // for hashed files
setHeaders: (res, path) => {
if (path.endsWith('.html')) {
res.setHeader('Cache-Control', 'no-cache, must-revalidate');
} else {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
}
}
}));
何时用强制刷新/清除缓存
- 紧急修复:CDN purge 或发布新带 hash 的文件
- 大范围破坏性改动:短期 s-maxage 在边缘生效,配合版本化逐步切换
结尾建议(一步落地)
1) 在构建管道加入文件指纹(hash)并引用这些文件。
2) 把静态资源 Cache-Control 改为 public, max-age=31536000, immutable;把 HTML 改为 no-cache, must-revalidate 并保留 ETag。
3) 在发布时检查 CDN 缓存命中和必要的 purge 配置。
按这张清单改动后,日常发布会更顺畅,用户也能同时获得更快加载和及时更新。需要我把这些配置转换成你当前项目(例如 Nginx + Cloudflare 或 S3 + CloudFront)的具体示例吗?