1 缓存过程简要分析

浏览器使用缓存中的数据将数据存入缓存中的大致流程为:

  • 浏览器每次发起请求时,首先在浏览器缓存中查找是否存在要请求的资源及其缓存标识(浏览器缓存资源时,通常会附带相应的缓存标识)。
  • 如果存在缓存资源及其缓存标识,则浏览器根据缓存控制策略(例如 Cache-Control 头信息)确定是否可以使用该缓存资源
  • 如果根据缓存控制策略不能使用缓存资源,浏览器会向服务器请求该资源。同时,如果服务器在响应中指示可以缓存该资源,则浏览器会将响应资源及其缓存标识存入浏览器缓存中

2 浏览器的缓存策略

浏览器通过强制缓存协商缓存这两种策略实现资源的缓存。

2.1 强制缓存

  • 解释:当浏览器向服务器发送请求时,服务器返回资源的同时,会使用 ExpiresCache-Control 响应头来控制是否缓存对应的资源。其中 Expires 的优先级 < Cache-Control 的优先级。通过上述这种方式实现的缓存就称之为强制缓存。

  • 使用场景:所谓强制缓存的使用,就是指,浏览器发送请求时,先在浏览器缓存中查找缓存数据及其标识,并根据缓存规则来决定是否使用该缓存数据的过程。强制缓存分为以下三种使用场景。

    场景 描述 图解
    不存在缓存数据及表示 强制缓存失效,浏览器直接向服务器发起请求 image-20240603235434460
    存在缓存结果及标识;但缓存结果已失效(由于过期等原因) 强制缓存失效,浏览器使用协商缓存 image-20240603235613430
    存在缓存结果及标识;且缓存结果未失效 浏览器直接返回缓存结果 image-20240603235731516
  • Expires 响应头:该响应头在 HTTP/1.0 中用于控制缓存。

    • 取值:对应资源缓存的到期时间。每次浏览器发送请求时,如果在浏览器缓存中找到了对应的缓存资源,则需要将客户端时间和过期时间进行对比。如果客户端时间 < 过期时间,则直接使用缓存结果,否则直接向服务器发送 HTTP 请求,获取对应的资源。

      1
      Expires: Mon, 16 Apr 2018 01:41:50 GMT
    • 缺点:该响应头被废弃的原因在于,Expires 控制缓存的原理为将客户端的时间与服务端的时间做对比,一旦二者时间不同步,此时缓存资源的过期时间将不再有意义。因为在 Cache-Control 中,将绝对的时间修改为相对的时间,避免客户端和服务端时间不同步带来的问题。

  • Cache-control 响应头:该响应头在 HTTP/1.1(当前常用) 中用于控制缓存。

    • 取值

      取值 含义
      public 所有内容都被缓存;客户端和代理服务器都可以缓存
      private 默认值:所有内容都被缓存;只有客户端才能缓存
      no-cache 所有内容都被缓存;只有客户端才能缓存;是否使用缓存需要经过协商缓存来决定
      no-store 所有内容都不会被缓存
      max-age=xxx 所有缓存的内容将在 xxx 秒后失效
  • 对比:强制缓存的两种实现

    区别 Expires Cache-Control
    时间值 绝对值 相对值
    优先级

    如果同时使用 ExpiresCache-Control 实现强制缓存,则只有 Cache-Control 生效。

2.2 协商缓存

  • 解释:当浏览器请求强制缓存中的缓存数据时,如果存在缓存数据及其标识,但缓存结果失效,此时浏览器无法确定该缓存数据是否仍然有效。在这种情况下,浏览器会携带对应的资源标识发送 HTTP 请求,以确认缓存的数据是否与服务器上的数据一致。如果数据一致,服务器会返回 304 状态码,告诉浏览器可以继续使用缓存中的数据;如果数据不一致,服务器会返回 200 状态码,并提供最新的数据。通过这种方式访问缓存中的数据的方式称之为协商缓存。

  • 使用场景:所谓协商缓存的使用,指的是当浏览器在缓存中找到失效的缓存数据后,通过向服务器发送请求来确认缓存数据是否仍然有效的一种缓存机制。协商缓存分为以下两种适用场景。

    场景 描述 图解
    协商缓存生效 服务端返回 304 响应,通知客户端可以使用缓存中的对应数据 image-20240604000748403
    协商缓存失效 服务端返回 200 响应,返回给客户端最新的数据
  • Last-Modified 响应头和 If-Modified-Since 请求头:用于控制协商缓存。

    • 响应头 Last-Modified:服务器在响应请求时,通过该响应头返回资源文件在服务器中最后被修改的时间
    • 请求头 If-Modified-Since:客户端在发送请求时,携带此请求头,其内容为上次响应中返回的 Last-Modified 值,用于告诉服务器对应资源上次请求返回的最后修改时间。服务器收到请求后,会将 If-Modified-Since 的值与资源在服务器中最后的修改时间进行对比。如果服务器上的资源最后修改时间晚于该请求头的值,则重新返回资源,状态码为 200;否则返回 304,表示缓存资源没有更新,可以继续使用缓存文件。
  • Etag 响应头和 If-None-Match 请求头:用于控制协商缓存。

    • 响应头 Etag:服务器在响应请求时,通过该响应头返回资源文件的唯一标识
    • 请求头 If-None-Match:客户端在发送请求时,携带此请求头,其内容为上次响应中返回的 Etag 值,用于告诉服务器对应资源上次请求返回的唯一标识值。服务器收到请求后,会将 If-None-Match 的值与资源在服务器中的 Etag 进行对比。不一致则重新返回资源,状态码为 200;一致则返回 304,表示缓存资源没有更新,可以继续使用缓存文件。
  • 对比:协商缓存的两种实现

    • Etag/If-Not-Match 优先级高于 Last-Modified/If-Modified-Since,同时存在则只有 Etag/If-Not-Match 生效。

3 浏览器缓存的存放位置

  • 存放位置:浏览器可以将其缓存存放在内存中(memory cache),也可以存放在硬盘中(disk cache)

  • 缓存分类:根据缓存的存放位置,可以将缓存分为内存缓存硬盘缓存

    一般来说,浏览器会根据资源的大小、使用频率等因素,将 JS、图片和 CSS 等资源存放在内存缓存或硬盘缓存中。频繁访问的小型资源通常存放在内存缓存中,而较大的资源则可能存放在硬盘缓存中。每次刷新页面时,浏览器会优先从内存缓存中读取资源,如果没有找到,则会从硬盘缓存中读取。

  • 缓存的读取顺序内存缓存 => 硬盘缓存

    举例理解:当我们首次访问一个 URL 时,浏览器会缓存响应中允许缓存的数据。关闭浏览器后,对应的缓存数据会被写入到硬盘中。下一次打开浏览器,加载对应网页时,浏览器会首先从硬盘缓存中读取缓存数据。如果此时刷新网页,浏览器则会从内存中读取缓存数据。

4 第一次 HTTP 请求对于浏览器缓存的意义

当浏览器第一次请求资源时,服务器通常会在响应中返回一些与缓存相关的头部字段,这些字段用于指导浏览器如何缓存该资源。这些头部字段包括但不限于 Last-ModifiedExpiresCache-ControlETag

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Date: Mon, 03 Jun 2024 10:00:00 GMT
Last-Modified: Mon, 01 Jun 2024 10:00:00 GMT
Expires: Mon, 10 Jun 2024 10:00:00 GMT
Cache-Control: max-age=604800
ETag: "abc123"
Content-Type: text/html
Content-Length: 1234

5 总结:浏览器的缓存机制

  • 强制缓存优先于协商缓存。强制缓存生效则直接使用缓存数据,否则进行协商缓存。
  • 协商缓存由服务器决定是否使用缓存中的数据。协商缓存生效则服务器返回 304,使用缓存数据,否则重新请求结果,再存入浏览器缓存中。
image-20240604003331630

REFERENCES

https://juejin.cn/post/6844903593275817998