头图

发版后有人说“怎么还是老页面”,很多人第一反应是让 CDN 全量刷新。面试里要是只答这句,基本等于没开始排。

我通常先问一句:他拿到的 HTML 是新的,还是 HTML 里引用的 JS 还是旧的?

这两个答案,后面完全是两条路。

从入口文件往下走,缓存问题会自己分叉

假设这次发布改了一个按钮文案。你在本机看是新的,用户刷新几次还是旧的。打开 DevTools 的 Network,先盯住文档请求,也就是通常的 index.html

如果它的响应里仍然引用:

<script src="/static/js/app.7d3e2.js"></script>

那先别去看 JS 文件。入口 HTML 被缓存住了,浏览器压根不知道新构建已经产出了 app.a91f0.js

我会把入口文件设成可重新验证,而不是一年不动:

Cache-Control: no-cache

这里的 no-cache 容易被误解。它不是不允许缓存,而是每次使用前要和服务端确认。对 HTML 入口,这个语义很合适。

静态资源反过来。带内容 hash 的文件名本来就应该缓存久一点:

Cache-Control: public, max-age=31536000, immutable

前提只有一个:文件名真的会随着内容变。Webpack 里常见的是:

output: {
  filename: "static/js/[name].[contenthash:8].js",
}

旧的 app.7d3e2.js 可以一直留在缓存里,新页面会去请求 app.a91f0.js。真正危险的不是“缓存太久”,而是文件内容变了,路径却还是 app.js。这时 CDN、浏览器和发布机器都可能各自留着一个版本,排起来很痛苦。

还有一层经常被漏掉:Service Worker。

如果 Network 里 HTML 和 JS 的响应都已经是新版本,页面却还是旧状态,我才去看 Application 面板里的 Service Workers 和 Cache Storage。它可能还在返回旧的 app shell。这个时候不要机械地加 skipWaiting 就结束,先确认新 worker 是否已经激活、当前页面受谁控制、缓存名有没有随版本更新,再决定清理策略。

浏览器、CDN 与带 hash 静态资源的缓存排查链路

面试官要的是排查顺序,不是一串缓存名词。我会这样收口:

入口 HTML 不做长期强缓存,带内容 hash 的静态资源可以长期缓存;如果响应都对但 UI 还是旧,再独立查 Service Worker。


威武的凉茶
1 声望0 粉丝