HTTP 缓存机制演进史:从绝对时间到内容指纹的技术变革

公開日: 2026-03-01 19:56 1442文字 8 min read

smile丶snow avatar

smile丶snow

大三/前端开发/百合汉化组成员/百合/偶尔也会做些动态壁纸

2026.03 - 至今
快手
前端开发实习生
2025.12 - 2026.03
北京蓝色光标数字传媒
前端开发实习生
この投稿は「日本語」では表示できません。元の投稿を表示しています。
浏览器缓存机制可以从 HTTP 协议演进的上下文来看。从 HTTP/1.0 的 Expires 和 Last-Modified,到 HTTP/1.1 的 Cache-Control 和 ETag,每一次演进都是对前代缺陷的精准修复。本文将带你理解强缓存与协商缓存背后的技术演进逻辑。

第一阶段
/1.0 时代与 Expires 的致命缺陷

🕰️ 背景 (Context)

在早期的 Web 时代(1996 年左右,HTTP/1.0),网页多是纯静态文档,网速极慢。为了减少服务器压力和加快页面加载,W3C 和 IETF 的专家们决定在浏览器里加个本地缓存

🛠️ 解决方案
(强缓存)

服务器在下发资源时,在 HTTP 响应头里加上一个绝对时间:

Expires: Wed, 21 Oct 2026 07:28:00 GMT

浏览器的脑回路很简单:“在这个绝对时间点到来之前,我再要这个文件,就不找服务器了,直接从本地硬盘读。”

💥 核心痛点 (为什么必须演进?)
依赖的是客户端本地的系统时间!

如果用户的电脑主板电池没电了,或者用户自己把电脑时间调到了 2027 年,那么这个缓存机制就瞬间全部失效,或者永远都不去请求新资源。

依赖客户端时间来做服务端缓存控制,在工程上是一个极其脆弱的设计。


第二阶段
/1.1 时代与 Cache-Control 的救场

🕰️ 背景 (Context)

1999 年,HTTP/1.1 规范发布。互联网变得更加动态,专家们痛定思痛,决定彻底解决客户端时间不准导致的缓存车祸。

🛠️ 解决方案
(强缓存 2.0)

不再使用绝对时间,而是引入了**相对时间(滑动窗口)**的概念:

Cache-Control: max-age=3600

浏览器的脑回路变成了:“从我接收到这个文件的这一秒开始算,接下来的 3600 秒(1 小时)内,我直接用本地缓存。”

💡 上下文的精妙之处 (面试核弹)

  • 完美避坑:max-age 彻底摆脱了对客户端系统时钟的依赖,依靠相对倒计时,完美解决了 Expires 的缺陷。
  • 向下兼容与优先级
    HTTP/1.0 浏览器,现代服务器通常会同时下发 Cache-ControlExpires。但在 HTTP/1.1 规范中被硬性规定:只要 Cache-Control 存在,Expires 就会被无视。这就是为什么面试题里会有”优先级谁高”的由来——不是凭空定规矩,而是新旧时代的权力交接。

第三阶段
? —— 协商缓存的演进

强缓存(max-age)虽然爽,但倒计时总有结束的时候。

倒计时结束后,浏览器必须去问服务器:“老哥,这个文件更新过吗?”

这就引出了协商缓存,而它同样经历了一次从 HTTP/1.0 到 1.1 的填坑演进。

填坑前
/1.0 的 Last-Modified (基于修改时间)

做法

服务器首次返回文件时,带上 Last-Modified: [文件最后修改的绝对时间]。缓存过期后,浏览器拿着这个时间去问服务器(通过 If-Modified-Since 请求头):“从这个时间之后,文件改过吗?”

如果没改,服务器返回 304 Not Modified,告诉浏览器继续用旧文件。

痛点 (为什么又不行了?)

  1. 精度太粗
    。如果一个文件在 1 秒内被修改了 5 次,Last-Modified 根本察觉不到,会导致用户拿到旧文件。
  2. 内容没变,但时间变了
    ,哪怕文件内容连一个标点符号都没变,修改时间也会变,导致浏览器傻傻地重新下载。

填坑后
/1.1 的 ETag (基于内容指纹)

为了解决时间的精度和误判问题,HTTP/1.1 再次引入了终极杀器

做法

服务器直接根据文件的内容,计算出一个哈希值(指纹),比如:

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

优势

缓存过期后,浏览器拿着这个指纹去问服务器(If-None-Match)。服务器只要重新算一下当前文件的指纹对比一下就行。

  • 只要内容改了哪怕一个字节,指纹绝对不同
  • 内容没变,哪怕修改时间变了一万次,指纹也一样

优先级重演

正如 Cache-Control 压制 Expires 一样,由于指纹比时间更精准,ETag 的优先级也硬性高于 Last-Modified


总结
”上下文”征服面试官的话术

“浏览器缓存可以从 HTTP 协议演进的上下文来看。它主要分为强缓存协商缓存

HTTP/1.0 时代,强缓存靠 Expires 的绝对时间,协商缓存靠 Last-Modified 的修改时间。但这俩都有致命的工程缺陷

,后者精度只能到秒且无法识别内容本质的改变。

所以 HTTP/1.1 针对这两个痛点进行了重构

Cache-Control: max-age 这个相对时间来替代 Expires,同时引入了基于内容哈希的 ETag 来弥补 Last-Modified 的缺陷。为了保证平滑过渡和向下兼容,协议规范硬性指定了新机制的优先级高于老机制。

最终在浏览器里的运作流程就是

Cache-Control 决定要不要发请求;如果要发,就带上 ETag 去服务端进行指纹协商,根据状态码是 200 还是 304 来决定是重新下载还是复用本地资源。“

缓存工作流程图

用户请求资源

检查本地缓存是否存在

存在 → 检查 Cache-Control (max-age)

未过期 → 直接使用本地缓存 (强缓存命中)

已过期 → 发起协商缓存请求

携带 If-None-Match (ETag) 或 If-Modified-Since

服务器对比

    ├─ 304 Not Modified → 继续使用本地缓存
    └─ 200 OK → 下载新资源并更新缓存
© 2024 - 2026 smile丶snow @YukiBloom
Powered by theme astro-koharu · Inspired by Shoka