HTTP缓存实战排查清单
为什么线上总是“明明发版了却没生效”
前端资源更新后,用户仍然看到旧页面,通常不是发布失败,而是缓存策略没有设计好。HTTP 缓存本质上是一个性能与一致性的平衡问题:缓存命中越高,性能越好;资源更新越快,缓存越难长期命中。
排查这类问题不要先改代码,先看三个事实:
- 浏览器到底请求了什么 URL。
- 服务器返回了什么缓存头。
- CDN 是否改写了源站响应。
核心机制:强缓存与协商缓存
强缓存命中时,浏览器不会向服务器发请求,常见头:
Cache-Control: max-age=31536000, immutableExpires: ...
协商缓存会发请求,但可返回 304,常见头:
ETag+If-None-MatchLast-Modified+If-Modified-Since
实践里优先使用 Cache-Control 与 ETag。Last-Modified 受文件时间粒度影响,频繁发布时容易误判。
可直接套用的资源分层策略
HTML
- 建议:
Cache-Control: no-cache - 原因:HTML 是入口,必须尽快拿到最新版。
JS/CSS/字体等静态资源
- 文件名带内容哈希,如
app.a1b2c3.js - 响应头:
Cache-Control: public, max-age=31536000, immutable - 原因:一旦文件名变更,旧缓存自然失效。
API 响应
- 登录态、用户私有数据:
Cache-Control: no-store - 公共配置、低频变更数据:短
max-age+ 协商缓存
5步排查流程(按顺序)
第一步:在浏览器 Network 看“真实请求”
- 是否命中
from memory cache/from disk cache - 状态码是否
304 - 是否有 Service Worker 接管
第二步:确认 URL 是否可区分版本
如果 URL 不变,且又用了长缓存,用户拿旧文件是预期行为。
第三步:核对响应头
重点核对:
Cache-ControlETagVaryAge(经 CDN 时)
第四步:检查 CDN 行为
常见问题:
- CDN 默认缓存了 HTML
- 回源时剥离了
ETag - 忽略查询参数导致多版本资源被当成同一个对象
第五步:回归验证
至少验证 3 类场景:
- 首次访问
- 普通刷新
- 强制刷新
常见误区
- 误区 1:只改
Expires不改Cache-Control。 - 误区 2:静态资源不用哈希,仅靠“清缓存通知用户”。
- 误区 3:把所有接口都设成
no-store,导致性能明显下降。 - 误区 4:忽略移动端 WebView 的缓存行为差异。
一份可执行清单
- HTML 入口禁止强缓存。
- 静态资源强缓存 + 文件名哈希。
- API 按数据敏感度分层缓存。
- 建立发布后缓存巡检:抽查首页 + 2 个核心业务页。
- 线上故障 SOP:先取响应头证据,再改配置。
总结
缓存问题本质上是“版本控制问题”。只要入口及时更新、静态资源可版本化、CDN 策略与源站一致,绝大多数“发布不生效”都可以被流程化解决。