浏览器缓存
✅ 一、HTTP 缓存的工作流程(简化):
浏览器请求一个资源(如 JS、CSS)
浏览器根据 HTTP 响应头(如
Cache-Control: max-age=3600
)判断:如果资源未过期 → 直接使用本地缓存(强缓存,200 from cache)
如果可能过期 → 发送请求到服务器,携带标识(如 If-Modified-Since / ETag)
服务器判断资源未变 → 返回 304 Not Modified(协商缓存)
服务器判断资源已变 → 返回 200 + 新资源
✅ 二、浏览器缓存概述(先给整体概念)
什么是浏览器缓存?
浏览器缓存是浏览器为了提升页面加载速度、减少网络请求、降低服务器压力,而将一些静态资源(如 JS、CSS、图片等)存储在本地的一种机制。
缓存分为两大类:
强缓存(也叫本地缓存 / 强制缓存 / Cache-Control 缓存)
协商缓存(也叫验证缓存 / 304 缓存 / Etag / Last-Modified 缓存)
✅ 三、1. 强缓存(Cache-Control / Expires)
强缓存是指浏览器在请求某个资源时, 不发送请求到服务器,直接从本地缓存中读取资源,前提是缓存没有过期。
浏览器不向服务器发请求
速度快,减少网络开销
如果缓存有效,HTTP 状态码是 200
✅ 强缓存相关的 HTTP 响应头:
(1)Expires
(较老的、基于绝对时间的方案,不推荐了)
Expires: Wed, 21 Oct 2025 07:28:00 GMT
表示这个资源的缓存 在这个时间之前都有效
问题是:它使用的是 服务器时间,如果客户端时间不准,可能会出错
已被 Cache-Control 取代
(2)Cache-Control
(现代主流方案,更灵活、更强大)
常用指令:
指令 | 说明 |
---|---|
| 资源缓存有效期为 3600 秒(1小时),在此时间内浏览器直接使用缓存,不请求服务器 |
| 不使用强缓存,但可以使用协商缓存(即要去服务器验证是否过期) |
| 完全不缓存,每次都要重新请求(最严格,用于敏感数据) |
| 表示资源可以被任何中间人(如 CDN、代理)缓存 |
| 表示资源只能被浏览器缓存,代理/CDN 不可缓存 |
✅ 最常用组合:
Cache-Control: public, max-age=31536000
表示:这个资源可以被任何人缓存,有效期是 1 年,在此期间浏览器直接使用本地缓存,不去请求服务器!
✅ 强缓存的缓存命中表现:
浏览器 不会发出任何网络请求
在 Chrome DevTools 的 Network 面板中,Size 会显示:
from disk cache
from memory cache
✅ 四、2. 协商缓存(Last-Modified / ETag)
✅ 定义:
协商缓存是指:当强缓存失效(比如 max-age 过期了),或者浏览器没有强缓存时,浏览器会向服务器发送一个请求,但带上一些标识,询问服务器:“我本地这个缓存还能用吗?”
如果服务器说:“可以用,没变”,则返回 HTTP 304 Not Modified,浏览器 直接使用本地缓存。
如果服务器说:“变了”,则返回 HTTP 200 + 新的资源内容。
✅ 协商缓存的目的:
避免重复传输相同的内容
如果资源没有变化,只返回一个 304 状态码,节省带宽、提升速度
✅ 协商缓存的两种常见方式:
(1)基于时间:Last-Modified 和 If-Modified-Since
流程:
第一次请求:
服务器返回资源,并带上响应头:
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
表示这个文件最后修改时间
第二次请求(缓存过期后):
浏览器会带上请求头:
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
服务器收到后,判断文件是否有更新:
没更新 → 返回 304 Not Modified(不返回 body,浏览器用缓存)
有更新 → 返回 200 + 新资源
⚠️ 问题:
只能精确到秒级
如果文件在一秒内多次修改,可能误判
(2)基于内容指纹:ETag 和 If-None-Match(推荐 ✅)
ETag 是什么?
是服务器为资源生成的一个 唯一标识符(通常是哈希值,如 md5),用来精准标识资源内容
比如:
ETag: "abc123def456"
流程:
第一次请求:
服务器返回资源 + 响应头:
ETag: "abc123def456"
第二次请求:
浏览器发送请求头:
If-None-Match: "abc123def456"
服务器比对 ETag:
没变 → 返回 304 Not Modified
变了 → 返回 200 + 新资源
✅ 优点:
更精准,基于内容,不依赖时间
即使文件在一秒内多次改动,也能正确判断
✅ 协商缓存命中时:
HTTP 状态码是 304 Not Modified
不返回资源内容,只返回响应头
浏览器 直接使用本地缓存
在 Chrome DevTools 的 Network 面板中,你会看到:
Status: 304
Size: (from disk cache) 或很小
✅ 五、强缓存 vs 协商缓存 对比总结
特性 | 强缓存(Cache-Control / Expires) | 协商缓存(Last-Modified / ETag) |
---|---|---|
是否请求服务器 | ❌ 不请求(直接用本地缓存) | ✅ 请求,但可能返回 304 |
是否返回资源内容 | ✅ 返回(如果缓存有效) | ❌ 不返回(304 只返回 header) |
速度 | ⚡️ 最快(无网络请求) | ⚡️ 较快(可能只返回 header) |
配置 Header |
|
|
精准度 | 基于时间,可能不够精准 | 基于内容指纹,更精准 |
典型状态码 | 200 (from cache) | 304 Not Modified |
✅ 六、实际项目中的最佳实践(优化策略)
✅ 推荐缓存策略(尤其对静态资源,如 JS、CSS、图片):
HTML 文件:
不设置强缓存 或 设置 no-cache
因为 HTML 可能会更新,要能及时拉到最新的 JS/CSS
静态资源(JS、CSS、图片等):
设置强缓存:Cache-Control: public, max-age=31536000
加上文件名 Hash(如 main.abc123.js)
文件名变化 → 强制浏览器获取新资源
文件名不变 → 一直用缓存
协商缓存作为补充:
如果你不能使用文件名 hash,可以配合 ETag / Last-Modified 做兜底
✅ 七、面试官可能会追问的问题(一定要准备!)
1. 强缓存和协商缓存的区别是什么?
(你已经会了,要能清晰对比:是否发请求、状态码、配置方式、使用场景)
2. Cache-Control 有哪些常用指令?分别是什么意思?
比如:
max-age
、no-cache
、no-store
、public
、private
3. Expires 和 Cache-Control 有什么区别?为什么现在推荐用 Cache-Control?
Expires 是绝对时间,受客户端时间影响;Cache-Control 是相对时间,更可靠、功能更强大
4. 协商缓存中 ETag 和 Last-Modified 有什么区别?哪个更好?
ETag 更精准(基于内容哈希),推荐优先使用
5. 为什么静态资源要加 Hash?和缓存有什么关系?
加 Hash 后文件名变化,可以绕过强缓存,让浏览器拉取最新资源,是缓存更新策略的关键
6. 如何查看浏览器是否命中了强缓存或协商缓存?
打开 Chrome DevTools → Network 面板,看:
Size: from disk cache / from memory cache → 强缓存
Status: 304 → 协商缓存
7. 如何配置服务器的缓存头?(Nginx / CDN / Express)
比如 Nginx 中配置:
location ~* \.(js|css|png|jpg)$ {expires 1y;add_header Cache-Control "public, max-age=31536000, immutable";
}
8. 如果我不希望某个资源被缓存,该怎么设置?
使用:
Cache-Control: no-store
或
Cache-Control: no-cache
✅ 八、总结(面试回答模板 - 精简版)
浏览器缓存分为强缓存和协商缓存:
强缓存(Cache-Control / Expires):浏览器直接使用本地缓存,不请求服务器,配置
max-age
或no-cache
等,命中时返回 200(from cache),速度快,用于静态资源。协商缓存(Last-Modified / ETag):浏览器会向服务器发起请求,但携带标识询问资源是否变更,若未变更则返回 304,利用缓存,减少传输。
最佳实践:静态资源使用强缓存 + 文件名 Hash,HTML 使用 no-cache,合理配置服务器响应头,提升页面加载性能,降低服务器压力。
✅ 一句话终极总结:
强缓存让浏览器不请求服务器直接用本地资源,协商缓存让浏览器询问服务器资源是否变了,两者结合使用是前端性能优化的重要手段,也是面试中缓存相关问题的核心考点。