HTTP 缓存是前端性能优化的核心,目标是减少重复网络请求、降低服务器压力、提升页面加载速度。
一般来说分为强缓存和协商缓存两级策略
优先级上 强缓存 > 协商缓存。
强缓存(无需请求服务器,直接使用本地缓存)
浏览器判断本地缓存未过期,直接从缓存读取资源。
不发送任何 HTTP 请求到服务端,状态码为 200 OK (from memory cache / from disk cache)。
关键头部:Cache-Control(现代标准,优先级最高)
max-age=xxx:缓存有效时间(单位秒),是最常用配置,例如max-age=31536000代表缓存一年。public:所有节点(浏览器、CDN、代理服务器)都可缓存。private:仅浏览器客户端缓存,CDN/代理不缓存(适用于用户私有资源)。no-cache:不跳过协商缓存(不是禁用缓存,强制走协商验证)。no-store:完全不缓存(敏感数据专用,不存任何副本)。immutable:资源永久不更新,浏览器不会主动重新验证(极致优化)。
废弃头部:Expires,绝对时间戳,受本地时间误差影响,已被 Cache-Control 替代,仅做兼容。
在静态资源场景中比较常用,尤其是 JS/CSS/图片/字体等不频繁变更的文件。
协商缓存(需请求服务端验证,缓存过期后使用)
强缓存过期后,浏览器发送请求到服务端,验证资源是否更新:
- 未更新:服务端返回
304 Not Modified,浏览器继续用本地缓存; - 已更新:服务端返回
200 OK+ 新资源,浏览器更新缓存。
两组核心头部(配对使用)
Last-Modified / If-Modified-Since(基于时间)
- 服务端响应头返回
Last-Modified:资源最后修改时间; - 浏览器请求头携带
If-Modified-Since:把上次的修改时间回传服务端; - 缺陷:时间精度仅到秒级,秒内多次修改无法识别;文件修改但内容不变也会更新缓存。
ETag / If-None-Match(基于内容,优先级更高)
- 服务端响应头返回
ETag:资源内容的唯一哈希值/指纹(内容不变,ETag 不变); - 浏览器请求头携带
If-None-Match:把上次的 ETag 回传服务端; - 优势:精准识别内容变化,解决时间戳缺陷,是生产环境首选。
适用于 HTML 文件、频繁小幅更新的接口、动态资源等需要实时验证的资源。
缓存策略设计
1. 分层缓存方案
- 构建产物(JS/CSS/字体):开启强缓存
- 配置
Cache-Control: max-age=31536000, public, immutable; - 配合文件名哈希(
app.abc123.js),内容变更则文件名变化,强制刷新缓存。
- 图片/静态媒体:开启强缓存 + 长周期
- 小图用 Base64 内联,大图 CDN 加速 + 长缓存。
- HTML 入口文件:开启协商缓存 / 禁用强缓存
- 配置
Cache-Control: no-cache,保证每次访问都验证最新版本。
- 敏感接口/动态数据:禁用缓存
- 配置
Cache-Control: no-store,杜绝数据泄露。
2. ETag 设计细节
生产环境推荐用弱 ETag(W/ 前缀),不校验字节完全一致,仅校验内容语义,降低服务端计算开销。
配合 Nginx 自动生成,无需业务代码开发。
想要强制更新可以采用文件名哈希、URL 加版本号(?v=1.0)的方案。
1分钟面试简洁版
HTTP 缓存分为强缓存和协商缓存,是前端性能优化的核心手段。
强缓存优先级最高,浏览器直接用本地缓存,不请求服务端,核心靠 Cache-Control,比如设置 max-age 控制过期时间,适合图片、JS/CSS 等带哈希的静态资源,配置长周期强缓存。
协商缓存在强缓存过期后使用,浏览器发请求给服务端验证,未更新返回 304,核心用 ETag/If-None-Match,基于内容哈希精准判断,比时间戳的 Last-Modified 更可靠,适合 HTML 入口文件。
策略设计上:静态资源开启长时强缓存+文件名哈希,HTML 用协商缓存,敏感数据用 no-store 禁用缓存,这样兼顾性能和更新实时性。