秋招之前本人不想再做强缓存和协商缓存的笔记了,已经写了四五遍了,真的很头疼我这坏习惯。都是因为我记笔记太混乱了,每次都找不到自己记得笔记,然后就只能能重新再记一遍。
一、先搞懂「强缓存优先」的核心逻辑
强缓存和协商缓存是 HTTP 缓存的两个层级,浏览器会按「先查强缓存 → 强缓存失效再查协商缓存」的顺序判断,「优先」就是指:
只要强缓存的条件满足(比如资源还在max-age有效期内),浏览器连请求都不会发给服务器,直接从本地缓存取;只有强缓存过期了,才会发请求走协商缓存流程。
二、强缓存和协商缓存「不是必须同时配置」,可只配一种
1. 只配强缓存(最常见)
- 配置方式:只设置
Cache-Control(推荐)或Expires,比如:Cache-Control: max-age=86400 // 缓存1天 - 适用场景:静态资源(如图片、字体、不常更新的 JS/CSS),这类资源更新频率低,优先减少请求数。
- 缺点:强缓存有效期内,就算服务器资源更新了,浏览器也拿不到新资源(除非用户手动清缓存/刷新)。
2. 只配协商缓存
- 配置方式:不设置
Cache-Control: max-age,只返回Last-Modified + ETag,比如:Last-Modified: Tue, 28 Nov 2025 10:00:00 GMT ETag: "abc123" - 适用场景:资源更新频率高(如首页接口数据),需要每次确认服务器资源是否最新,但又想减少重复传输。
- 缺点:每次都要发请求到服务器(只是命中时返回 304,不传输正文),比强缓存多了网络往返。
3. 同时配置(最优解,实际项目主流)
- 配置示例:
Cache-Control: max-age=3600 // 先强缓存1小时 Last-Modified: Tue, 28 Nov 2025 10:00:00 GMT ETag: "abc123" - 逻辑:1小时内直接读本地缓存(强缓存);1小时后发请求,服务器对比
Last-Modified/ETag,没更新就返回 304(协商缓存),更新了才返回新资源。 - 优势:兼顾「少请求(强缓存)」和「资源新鲜(协商缓存)」,是前端性能优化的常规操作。
三、面试速记结论
- 强缓存优先 = 浏览器先判断强缓存是否生效,生效则无请求,失效才走协商缓存;
- 可只配一种:
- 只强缓存:适合静态、低频更新资源,省请求但更新不及时;
- 只协商缓存:适合高频更新资源,保证新鲜但每次发请求;
- 实际项目建议「强缓存+协商缓存」搭配,平衡性能和时效性。
强缓存和协商缓存都使用的请求判断流程:
强缓存 + 协商缓存 组合使用的完整请求流程
结合Cache-Control: max-age(强缓存) +ETag/Last-Modified(协商缓存)的配置,浏览器的请求流程分为首次请求、强缓存有效期内请求、强缓存过期后请求三个阶段,以下是带细节的流程图解:
前置配置(服务器响应头)
# 强缓存:资源缓存1小时(3600秒) Cache-Control: max-age=3600 # 协商缓存:文件唯一标识 + 最后修改时间 ETag: "abc123456" Last-Modified: Wed, 27 Dec 2025 10:00:00 GMT完整流程(分阶段)
阶段1:浏览器首次请求该资源
- 浏览器发送完整请求到服务器(无缓存,不携带任何缓存相关请求头)。
- 服务器处理请求,返回200 OK,同时在响应头带上
Cache-Control+ETag+Last-Modified。 - 浏览器接收响应:
- 保存资源到本地缓存;
- 记录缓存元信息(
max-age过期时间、ETag、Last-Modified)。
- 浏览器渲染资源。
阶段2:强缓存有效期内(1小时内)再次请求
- 浏览器检查缓存元信息:
max-age未过期 →强缓存生效。 - 浏览器不发送任何请求到服务器,直接从本地缓存读取资源。
- 控制台 Network 面板显示:
200 OK (from disk cache/memory cache)。 - 渲染资源(全程无网络请求)。
阶段3:强缓存过期后(1小时后)再次请求
- 浏览器检查缓存元信息:
max-age已过期 →强缓存失效,进入协商缓存流程。 - 浏览器自动在请求头携带缓存验证字段:
# 对应 ETag 的验证字段 If-None-Match: "abc123456" # 对应 Last-Modified 的验证字段 If-Modified-Since: Wed, 27 Dec 2025 10:00:00 GMT - 服务器接收请求,对比验证字段:
- 情况A:资源未更新(ETag/Last-Modified 一致)
- 服务器返回304 Not Modified,响应体为空(节省带宽);
- 浏览器更新本地缓存的
max-age过期时间(重新开始计时); - 浏览器从本地缓存读取资源并渲染。
- 情况B:资源已更新(ETag/Last-Modified 不一致)
- 服务器返回200 OK,带上新资源 + 新的
ETag+ 新的Last-Modified; - 浏览器覆盖本地旧缓存,记录新的缓存元信息;
- 浏览器渲染新资源。
- 服务器返回200 OK,带上新资源 + 新的
- 情况A:资源未更新(ETag/Last-Modified 一致)
流程总结图(文字版)
首次请求 浏览器 →(无缓存头请求)→ 服务器 →(200+Cache-Control+ETag+Last-Modified)→ 浏览器 → 缓存+渲染 强缓存有效期内请求 浏览器 → 检查max-age未过期 → 直接读本地缓存 → 渲染(无请求) 强缓存过期后请求 浏览器 → 检查max-age过期 → 带If-None-Match/If-Modified-Since请求 → 服务器 ↙️ 资源未更新(304) ↘️ 资源已更新(200+新缓存头) 浏览器更新缓存有效期 浏览器覆盖旧缓存 ↘️ ↙️ 读取缓存/新资源 → 渲染面试关键要点
- 强缓存生效时无请求,协商缓存无论命中与否都有请求(304 无响应体,传输更快)。
- 协商缓存的请求头是浏览器自动携带的,无需前端手动设置。
ETag优先级高于Last-Modified(解决文件修改时间秒级内变更的问题)。
需要我帮你整理缓存相关的面试易错点吗?比如no-cache和no-store的区别、用户刷新对缓存的影响。(。。。)