强缓存 vs 协商缓存

一句话总结

强缓存是浏览器自己说了算——过期时间内直接用缓存,不跟服务器打招呼。协商缓存是浏览器问服务器”我这个缓存还能用吗”——服务器说行就用,不行就重新下载。强缓存快但可能用旧数据,协商缓存慢一点但保证最新。


🌰 先搞懂:浏览器为什么要缓存

你打开一个网页,里面有一张图片 logo.png。

第二次打开同一个网页。如果每次都要重新下载这张图片,那你每次打开网页都要等几秒。

实际上:

  • 第一次打开:下载 logo.png(200ms)

  • 第二次打开:浏览器直接从硬盘加载缓存的 logo.png(5ms)

  • 快了 40 倍

缓存的核心作用就一个:已经下载过的资源,不要重复下载。

两种缓存的工作流程


graph TD

    A["浏览器请求一个资源(比如 style.css)"] --> B{"有没有缓存?"}

    B -->|"没有"| C["直接去服务器下载 ✅"]

    B -->|"有"| D{"缓存还有没有过期?<br/>(强缓存)"}

    D -->|"没过期"| E["直接用缓存,不请求服务器 ✅<br/>200 from disk cache"]

    D -->|"过期了"| F{"问服务器:这个缓存还能用吗?<br/>(协商缓存)"}

    F -->|"服务器说没变"| G["用缓存 ✅<br/>304"]

    F -->|"服务器说变了"| H["重新下载 ✅<br/>200"]


一、强缓存(不需要问服务器)

强缓存 = 浏览器自己判断:“这个文件还没过期,直接用。”

整个过程完全不和服务器通信。浏览器看到过期时间还没到,直接从本地磁盘加载。速度最快,因为连网络请求都没发。

像什么? 你家的冰箱里有昨天的剩饭。你看了一眼生产日期,今天没过期。直接拿出来热了就吃(强缓存)。不用打电话问饭店”这饭还能吃吗”。

强缓存怎么控制?

服务器在返回 HTTP 响应时,通过响应头告诉浏览器缓存多久。

方式一:Expires(HTTP/1.0)

 
Expires: Wed, 09 Jul 2026 12:00:00 GMT
 

→ “这个资源在 2026 年 7 月 9 日 12 点之前都有效”

问题:用的是绝对时间。服务器和浏览器时钟不一致 → 缓存可能提前过期或过期了还在用。

方式二:Cache-Control(HTTP/1.1,现在都用这个)

 
Cache-Control: max-age=3600
 

→ “这个资源从你收到开始算 1 小时内有效”

用的是相对时间(从你拿到的那一刻开始算)。不管你在哪个时区,从你拿到开始倒计时 3600 秒。不依赖服务器和客户端时间一致。

现在一般不用 Expires 了,都用 Cache-Control: max-age。

强缓存生效时你看到什么?

打开浏览器开发者工具(F12)→ Network 标签。

看到某个请求的 Status 是:

  • (disk cache) ← 从硬盘缓存的

  • (memory cache) ← 从内存缓存的

  • (from cache) ← 强缓存命中,根本没有发请求

Size 那一列显示:from disk cachefrom memory cache。大小是 0(因为没有从网络下载)。


二、协商缓存(需要问服务器)

强缓存过期了,或者你设了 no-cache。浏览器不确定缓存还能不能用。于是问服务器:“我这个缓存版本还能用吗?”

  • 如果服务器说”没变”:返回 304 Not Modified。不返回资源本身(省流量)。浏览器用自己的旧缓存

  • 如果服务器说”变了”:返回 200 OK + 新的资源内容。浏览器用新的,更新缓存

协商缓存有两种问法

方式一:按时间问(Last-Modified / If-Modified-Since)

服务器第一次返回资源时,在响应头里带上最后修改时间:

 
Last-Modified: Wed, 08 Jul 2026 10:00:00 GMT
 

→ “这个文件最后修改时间是 2026 年 7 月 8 日 10 点”

浏览器把这个时间记下来。强缓存过期后,浏览器发请求时带上:

 
If-Modified-Since: Wed, 08 Jul 2026 10:00:00 GMT
 

→ “这个文件在 2026 年 7 月 8 日 10 点之后有没有改过?”

服务器:

  • 没改过 → 304(用缓存)

  • 改过了 → 200 + 新文件

问题:

  1. 时间精度是秒。1 秒内改了两次,判断不出来

  2. 文件没改但服务器迁移了,时间变了,重新下载

方式二:按指纹问(ETag / If-None-Match)

服务器第一次返回资源时,给这个资源算一个”指纹”(哈希值):

 
ETag: "abc123xyz"
 

→ “这个文件的指纹是 abc123xyz”

指纹 = 对文件内容做哈希。内容变了,指纹就变。内容没变,指纹永远一样。

浏览器把这个指纹记下来。强缓存过期后,浏览器发请求时带上:

 
If-None-Match: "abc123xyz"
 

→ “这个文件的指纹还是 abc123xyz 吗?”

服务器:

  • 指纹没变 → 304(文件没改过,用缓存)✅

  • 指纹变了 → 200 + 新文件 + 新 ETag ✅

比 Last-Modified 精确(指纹变才是真变了)。

为什么两种都要?

ETag 更精确,但不是每个服务器都支持。所以 HTTP 标准让两者并存:

服务器同时返回 Last-Modified 和 ETag。浏览器同时发 If-Modified-Since 和 If-None-Match。服务器优先检查 ETag。ETag 一致再看 Last-Modified(或者只看 ETag)。

两种都带上,兼容所有服务器。


三、对比总结

强缓存协商缓存
要不要发请求不请求服务器,浏览器自己判断要请求服务器,问服务器”能用吗”
状态码200(from cache)304(Not Modified)
控制头Cache-Control: max-age=3600 / ExpiresETag / Last-Modified + If-None-Match / If-Modified-Since
速度最快(没网络请求)中等(有请求但没下载资源)
数据新鲜度可能用旧的(过期时间内不验证)永远是最新的(服务器确认过)
像什么冰箱里的剩饭,看日期没过期就吃打电话问饭店”这剩饭还能吃吗”

四、Cache-Control 的其他指令

不只 max-age,还有别的控制方式:

指令含义说明
no-cache每次都要问服务器缓存能不能用不是不缓存,是每次都要协商
no-store完全不缓存适合银行卡号、密码等敏感数据
public谁都可以缓存浏览器、CDN、代理服务器都能存
private只有浏览器可以缓存CDN 和代理不能存,适合用户个人信息
must-revalidate缓存过期后必须去服务器验证不能用过期的

五、实际项目中怎么配

不同的资源用不同的缓存策略。

资源类型缓存策略说明
HTMLCache-Control: no-cache时效性最强,每次都要最新的
CSS / JS(带哈希文件名)Cache-Control: max-age=31536000(一年)内容变了文件名就变,强缓存一年
图片 / 字体Cache-Control: max-age=2592000(一个月)一般不频繁变
API 接口Cache-Control: no-store数据实时性高,不缓存

一句话讲清

延伸提问:“强缓存和协商缓存有什么区别?”

“强缓存是浏览器自己判断——缓存没过期就直接用,不发任何网络请求。最快。控制头是 Cache-Control: max-age。

协商缓存是强缓存过期后,浏览器发请求问服务器’我这个缓存还能用吗’。服务器返回 304 就说继续用,返回 200 就说已经更新了,下载新的。控制头是 ETag / If-None-Match 和 Last-Modified / If-Modified-Since。

强缓存快但可能用旧数据,协商缓存慢一点但永远最新。两者配合使用:强缓存覆盖大部分时间,过期后再用协商缓存验证。“


记忆口诀

强缓存 = 没过期直接用,不发请求。Cache-Control: max-age 控制。

协商缓存 = 过期了问服务器,304 继续用旧,200 下载新的。ETag 按指纹判断。

强缓存快但可能旧,协商缓存新但慢一点。两者配合用。

no-cache 不是不缓存,是不用强缓存,每次都要协商。no-store 才是不缓存。

速记卡(面试闪卡)

Q1:一句话讲清「强缓存 vs 协商缓存」到底是什么?

A:强缓存是浏览器自己说了算——过期前直接用本地缓存、不跟服务器打招呼;协商缓存是过期后问服务器”还能用吗”。

Q2:强缓存怎么控制 —— 怎么理解?

A:像看保质期吃剩饭:浏览器看响应头里的 Cache-Control: max-age(相对时间,从拿到起倒计时 3600 秒,现主流)或老旧的 Expires(绝对时间点,怕时钟不一致)。没过期就直接从硬盘加载,连网络请求都不发。

Q3:协商缓存两种问法 —— 怎么理解?

A:像两种核对方式:时间派带 If-Modified-Since 问”这文件改过没”(比 Last-Modified 最后修改时间,秒级精度有坑);指纹派带 If-None-Match 问”指纹还是 abc123 吗”(ETag 是内容哈希,内容微调也能识别,更精准)。

Q4:304 和 200 怎么区分 —— 怎么理解?

A:服务器说”没变”回 304 Not Modified(不传资源,省流量,浏览器用旧缓存);说”变了”回 200 OK + 新内容。两种都正常,304 恰恰是协商缓存生效、帮用户省了一次下载的好消息。

Q5:Cache-Control 其他指令 —— 怎么理解?

A:像缓存的精细开关:no-cache 不是不缓存,是每次都要协商;no-store 才彻底不缓存(银行卡号密码用);public 谁都能存(CDN/代理),private 只有浏览器能存(用户隐私);must-revalidate 过期必须回服务器验。

Q6:核心速记主线有哪些?

  • 强缓存自己定:没过期直接读本地,控制头 Cache-Control / Expires

  • 协商缓存问服务器:ETag 指纹 vs Last-Modified 时间

  • 304 省流量、200 换新:两者都正常,304 是好事

  • 其他指令:no-cache 必协商、no-store 真不存、public/private 定范围

口诀

A:强缓存看日期,闷头就用它;

过期问一句,ETag 指纹查。

304 报平安,200 换新瓦;

no-cache 必协商,no-store 一点不拿。

相关链接