← 返回题目列表

HTTP 缓存在前端项目中如何设计?

高频 中等 第 13 / 26 题 更新于 2026/07/28
前端网络HTTP缓存强缓存协商缓存

简化版

前端缓存设计通常是 HTML 短缓存或不强缓存,带 hash 的 JS/CSS/图片长期强缓存,接口数据按业务设置缓存策略。强缓存减少请求,协商缓存减少传输,配合 CDN 和版本化文件名能兼顾性能和更新。

详细版

常见策略:

  • HTML:no-cache 或短缓存,确保能拿到最新资源引用。
  • JS/CSS:文件名带内容 hash,设置长期强缓存。
  • 图片字体:带 hash 可长期缓存,不带 hash 要谨慎。
  • API:根据业务设置 Cache-Control、ETag 或前端缓存。

如果 HTML 被长期缓存,用户可能一直引用旧 JS。
如果静态资源没有 hash 却长期缓存,发布后也可能不更新。

合理缓存要同时考虑性能、版本更新、回滚和 CDN 刷新。

完整版教学

一、缓存设计的核心矛盾

缓存越强,访问越快;缓存越强,更新越难。前端缓存设计就是在速度和更新之间找平衡。

带内容 hash 的资源天然适合长缓存,因为内容变了文件名也变。HTML 通常不适合长缓存,因为它是资源入口。

二、强缓存和协商缓存

强缓存命中时浏览器不请求服务器,速度最快。常由 Cache-Control: max-age=... 控制。

协商缓存会向服务器验证资源是否变化。如果没变,服务器返回 304,浏览器继续用本地缓存。

强缓存省请求,协商缓存省响应体。

三、发布顺序

前端发布常见顺序是先上传带 hash 的静态资源,再发布 HTML。这样可以避免 HTML 已经引用新资源,但 CDN 上新资源还不存在。

回滚时也要保证旧版本资源没有被删除,否则 HTML 切回旧版本后会引用不到旧文件。

四、面试追问与工程落地

面试官可能问:“为什么 index.html 通常不长期强缓存?”

因为它决定加载哪个版本的 JS/CSS。如果 HTML 缓存太久,用户可能一直停留在旧入口,无法拿到新版本。

工程中要结合 CDN 缓存、资源 hash、版本号和灰度发布一起设计缓存策略。

五、指令语义和缓存层次

no-cache 不是“不缓存”,而是复用前必须向源站验证;真正禁止存储使用 no-store。共享缓存和浏览器私有缓存还要区分:

指令语义常见场景
max-age=31536000, immutable一年内直接复用内容 hash 静态资源
no-cache可存储,每次复用前验证HTML 入口
no-store不得存储高敏感响应
private只允许私有缓存用户个性化数据
s-maxage=60共享缓存使用 60 秒CDN 公共 API/HTML

若 1MB JS 被访问 10000 次,长强缓存理论上可省近 10GB 响应体传输;但前提是 URL 内容不可变。文件名不变却缓存一年,节省的流量会换成无法及时修复线上代码的代价。

缓存设计不是给所有资源一个 TTL,而是同时设计“资源身份、谁能缓存、多久复用、如何验证、怎样失效”。

六、协商、Vary 和发布闭环

ETag 变化时返回新 200,不变时返回 304;Last-Modified 精度和语义较弱,通常作为另一种验证器。304 没有响应体,但请求往返仍存在,所以它不等于强缓存的零网络成本。

Cache-Control: public, max-age=31536000, immutable
ETag: "content-version"
Vary: Accept-Encoding

Vary 决定缓存 key 还受哪些请求头影响。缺少必要 Vary 可能把压缩格式、语言或 Origin 响应串用;Vary 维度过多又会碎片化缓存、降低命中率。

发布必须先保证新旧 hash 资源都可用,再更新 HTML。排查旧版本时查看 DevTools 的 from memory/disk cache、Age、ETag、CDN 命中头和最终 HTML 引用,分别判断浏览器、代理、CDN 或源站哪一层陈旧。

对于 Service Worker 缓存,还要单独设计版本和更新生命周期;它可以绕过普通 HTTP 缓存路径返回旧响应。排查时应确认请求究竟来自 HTTP cache、Cache Storage 还是网络。

若响应带用户身份或权限差异,还必须先确认共享缓存不会跨用户复用,再讨论命中率优化。

七、常见误区与追问

  • 误区:no-cache 表示浏览器完全不能保存。 它允许存储,但每次复用前必须验证。
  • 误区:304 和强缓存命中成本相同。 304 仍需一次网络往返,强缓存可直接本地复用。
  • 误区:资源带 hash 后可以立刻删除旧版本。 旧 HTML、回滚版本和已打开客户端仍可能请求旧 URL。
  • 追问:为什么 HTML 通常不设一年强缓存? 它是资源版本入口,长期陈旧会让用户一直引用旧 bundle。
  • 追问:privateno-store 有何区别? private 允许浏览器私有缓存,no-store 禁止任何缓存存储。
  • 追问:ETag 与 Last-Modified 如何选? ETag 更能表达内容版本,Last-Modified 简单但受时间精度和生成逻辑限制。
  • 追问:Vary 为什么可能降低命中率? 每个请求头取值组合都可能形成独立缓存对象。

八、加强记忆

  1. 资源身份:内容 hash 把“内容变化”转成“URL 变化”。
  2. 入口策略:HTML 可更新,hash 资源长期 immutable。
  3. 指令区分:no-cache 要验证,no-store 才是不存。
  4. 验证成本:304 省响应体但不省 RTT,强缓存两者都省。
  5. 共享边界:public/private/s-maxage 与 Vary 决定 CDN 是否安全复用。
  6. 发布保障:先资源后 HTML、保留旧资源、支持灰度和回滚。