Skip to content

目录

核心思想

网络请求是昂贵的,它消耗时间和带宽。最高效的请求就是不发送请求。HTTP 缓存机制是浏览器的一种"记忆能力",它让浏览器可以"记住"已经获取过的资源。当下次需要同一个资源时,浏览器可以根据一套规则,决定是从本地"记忆"中直接读取,还是需要去询问服务器资源是否更新。这就是减少请求的艺术。


类别一:强缓存

强缓存是最高效的方式。如果一个资源命中了强缓存,浏览器会直接从本地副本加载,根本不会向服务器发送任何请求。这在开发者工具的 Network 面板中,通常表现为 200 OK (from memory cache)200 OK (from disk cache)

1. 工作原理

当浏览器第一次请求一个资源时,服务器在返回资源的同时,会通过响应头 Cache-Control 告诉浏览器这个资源的"过期时间"。

2. 核心响应头:Cache-Control

这是 HTTP/1.1 中用于控制缓存的核心字段,它有几个关键指令:

  • max-age=<seconds>: 最重要的指令。指定资源在被视为"过期"之前,可以被缓存的最大时间(秒)。例如,max-age=31536000 表示缓存一年。
  • public vs private:
    • public: 表明响应可以被任何中间人(如 CDN、代理服务器)缓存。
    • private: 表明响应是针对单个用户的,只能被最终用户的浏览器缓存。
  • no-cache: 注意!不是"不缓存"的意思。它的意思是"不要使用强缓存,但在使用缓存副本前,必须去服务器验证一下它是否过期"(即,强制进入协商缓存阶段)。
  • no-store: 这才是"完全不缓存"。浏览器和任何中间缓存都不会存储这个响应的任何部分。常用于涉及敏感信息的请求。

类别二:协商缓存

当资源的强缓存"通行证"过期了,或者压根就没有设置强缓存(例如设置了 Cache-Control: no-cache),浏览器就必须向服务器发送一次请求来"协商"一下。浏览器会问:"我本地存的这个版本还能用吗?"

1. 工作原理

协商缓存需要浏览器和服务器之间的一次通信。浏览器在请求头中携带本地副本的"版本信息",服务器根据这个信息判断资源是否已更新。

  • 如果未更新:服务器返回一个 304 Not Modified 状态码,响应体为空。浏览器收到后,便安心地从本地加载缓存副本。这个过程虽然有一次请求,但由于没有下载资源本身,所以速度很快,极大地节省了带宽。
  • 如果已更新:服务器返回 200 OK 状态码,并在响应体中携带全新的资源内容,同时更新"版本信息"。

核对购物小票

  1. 保留小票:你(浏览器)买了一件衣服(资源),并保留了购物小票。小票上有两个重要信息:购买时间 和 商品唯一码。
  2. 拿着小票去询问:过了几天,你想知道这件衣服有没有出新款。你拿着小票去问店员(服务器):"我是在这个时间点买的、商品码是这个的衣服,现在还是最新的吗?"(发送带有 If-Modified-Since 和 If-None-Match 的请求)。
  3. 店员的回应:
  • 未出新款:店员看了一眼说:"没变,还是这个,你那个就是最新的。"(返回 304)。你便放心地继续穿旧衣服。
  • 已出新款:店员说:"哦,我们出新款了,你那个过时了。" 然后直接拿给你一件新款的衣服和一张新的小票。(返回 200 和新资源、新 ETag)。

2. 核心"版本信息"头

协商缓存依赖于两组配对使用的头部字段:

  • 第一组:基于时间戳
    • Last-Modified (服务器响应头): 资源在服务器上最后被修改的时间。
    • If-Modified-Since (浏览器请求头): 当浏览器发起协商请求时,会带上这个头,其值就是上次收到的 Last-Modified 的值。
  • 第二组:基于唯一标识
    • ETag (Entity Tag, 服务器响应头): 服务器为当前版本的资源生成的唯一标识符,像一个"指纹"。只要资源内容有变动,ETag 就会改变。
    • If-None-Match (浏览器请求头): 浏览器发起协商请求时,带上这个头,其值就是上次收到的 ETag 的值。

为什么 ETag 通常优于 Last-Modified?

ETag 更精确。Last-Modified 只能精确到秒,如果在 1 秒内文件被多次修改,Last-Modified 无法感知。此外,有时文件内容没有变,只是保存了一下,修改时间也会变,这会导致不必要的重新下载。ETag 基于文件内容生成,完美避开了这些问题。因此,ETag 的优先级更高。


总结:缓存决策流程

当浏览器需要一个资源时,它会按照以下顺序决策:

  1. 检查强缓存:查看本地副本的 Cache-Control: max-age 是否仍然有效。
  • 是 -> 命中强缓存。直接从本地加载,不发请求。 (最快)
  • 否 -> 进入协商缓存阶段。
  1. 发起协商缓存请求:向服务器发送一个请求,携带 If-Modified-Since 和/或 If-None-Match 头。
  • 服务器判断资源未改变 -> 返回 304 Not Modified。浏览器从本地加载。(较快)
  • 服务器判断资源已改变 -> 返回 200 OK 和新资源。浏览器使用新资源并更新本地缓存。(最慢,但必要)
特性强缓存协商缓存
是否联系服务器
HTTP状态码200 OK (from cache)304 Not Modified 或 200 OK
服务器响应304时响应体为空,200时为新资源
核心请求头(无)If-Modified-Since, If-None-Match
核心响应头Cache-ControlETag, Last-Modified
性能极高,无网络延迟较高,有网络延迟但节省带宽
适用场景长期不变的静态资源 (JS, CSS, 图片)可能会频繁更新的资源,或需要保证新鲜度的资源

基于 VitePress 的本地知识库