# HTTP 缓存

  • 缓存的规则
  • 缓存的方案
  • 缓存的优点
  • 不同刷新的的请求执行过程

# 缓存规则

用于缓存 JS、css、图片等资源,根据缓存阶段,分为两个强制缓存协商缓存

  • 强缓存协商缓存 同时存在,强缓存优先级高于协商缓存

  • 执行强缓存时,若命中,则直接使用缓存数据库数据 (即本地数据),不在进行缓存协商。

# 强制缓存

强缓存下,命中规则

+------------+                             +------------+
|  客户端     |  ------request---------->   |  缓存数据库  |
+------------+                             +------------+
    |                                           |
    |                                           |
+------------+                             +------------+
|  缓存数据库  |  <--有缓存,且为失效,返回数据  | 客户端      |
+------------+                             +------------+

问题:此时如何判断失效?

强缓存,为命中

+------------+                       +------------+  +------------+
|  客户端     | ------ request ---->  |  缓存数据库  |  |   服务器    |
+------------+                       +------------+  +------------+
      |                                     |               |
      | <------------ invalid ------------  |               |
      |                                                     |
      | --------------------- request --------------------> |
      |                                                     |
      | <-------- response Data and cache rule ------------ |
      |                                                     |
      | --------- saved cache rule to local db ------------ |

问题:此时的 cache rule 是什么?

# 协商缓存

客户端,从缓存数据库中获得到缓存数据的标识,得到标识后发起 request 到服务器,询问是否最新的?

  • 如果没有失效,服务器,返回 304,客户端直接从缓存中获得所请求的的数据?
    • (比如不加后缀的,即哈希值,容易返回 304)

问题:此时所说的 客户端直接从缓存中获得所请求的的数据 是从浏览器的那个缓存数据库吗?那为什么有些 304 显示 memory cachedisk cache,有些 304 则显示具体的 size 大小呢?

协商缓存下,命中规则

+------------+                       +------------+  +------------+
|  客户端     |                       |  缓存数据库  |  |   服务器    |
+------------+                       +------------+  +------------+
      |                                     |               |
      | ---------- 获取缓存数据的标识 ------>  |               |
      |                                                     |
      | <---------- 返回缓存数据的标识 ------  |
      |                                                     |
      | ----- 请求服务器验证缓存标识对应的数据是否已失效 --------> |
      |                                                     |
      | <-------------- 通知客户端缓存还未失效 ---------------- |
      |
      | -------------- 获取缓存数据---------> |

协商缓存下,未命中规则

+------------+                       +------------+  +------------+
|  客户端     |                       |  缓存数据库  |  |   服务器    |
+------------+                       +------------+  +------------+
      |                                     |               |
      | ---------- 获取缓存数据的标识 ------>  |               |
      |                                                     |
      | <---------- 返回缓存数据的标识 ------  |               |
      |                                                     |
      | ----- 请求服务器验证缓存标识对应的数据是否已失效 --------> |
      |                                                     |
      | <-------------- 返回最新数据和缓存的规则 -------------- |
      |                                                     |
      | ----- 将数据和规则都存入到系统 -------> |               |

# 缓存方案

在强缓存阶段: 客户端发起 HTTP 请求,主要是通过以下两个字段来与服务器获得缓存请求更换的。

  • Cache-controlcache-control: max-age=600

    • max-age=600,表示缓存的内容在 600 秒后失效
    • private:客户端可以缓存
    • public:客户端和服务器都可以缓存
    • max-age=t:缓存的内容将在 t 秒后失效
    • no-cache:需要使用协商缓存来验证缓存数据
    • no-store:所有内容都不缓存
    • Cache-Control: no-store, no-cache, no-transform, must-revalidate, max-age=0:比如 sockjs-node/info?t=1610684159275 中的请求
  • Expiresexpires: Fri, 15 Jan 2021 03:04:40 GMT

    • 返回服务器返回的数据的到期时间
    • 当再次请求时的请求时间小于返回的此时间,则直接使用缓存数据。(问题:此时的从什么地方使用缓存?服务器?客户端?)
    • 旧时代产物,由于时间 BS 时间误差,现在用 cache-control 替代

在协商缓存阶段

协商缓存,即和服务器进行协商。浏览器发起 HTTP 请求后,服务器将缓存标识和数据一起给客户端。客户端备份至自己的缓存中。 再次请求后,将带有的缓存标识也一并发给服务器,服务器据此作出判断,未失效则 304,客户端拿到该状态码直接使用缓存数据。

  • ETagETag: W/"5ffefa99-834c":服务器告诉浏览器当前资源在服务生成唯一标识。

    • ETag 比较昂贵,占用服务器资源。
    • If-None-Match
      • 不同:说明资源被改动过,整体返回响应体,200
      • 相同:资源 w 无心修改,直接读取客户端的缓存,响应 304
  • Last-modifiedLast-modified: Wed, 13 Jan 2021 13:50:17 GMT

    • 服务器在响应时,会告诉浏览器资源的最后修改时间。
    • (问题,这个时间如何判断?)
    • If-Modified-since:浏览器再次请求服务器的时候,请求头会包含此字段修改才下载
      • 与最后修改时间对比,一致返回 304
      • 从这个时间开始算起
      • 被修改:传输响应整体,200 Ok
      • 未修改:只传输响应 header,304 Not Modified
    • If-Unmodified-Since:从这个事件算起,是否文件没有被更改?属于未修改才下载
      • 被修改:不传输,服务器返回,412 Precondition failed (预处理错误)
      • 未修改:继续传输文件,200 Ok

在强缓存阶段:服务器响应的 header 中 Expires(逾期)Cache-Control 表示。

上图中,百度首页,有两个文件 (cd37ed75a9387c5b.jsd) 将 Cache-control 设置为极低:max-age=3600 甚至不设置。

而其他则设置极高 Cache-control: max-age=2592000,测试则从 memory-cache 中加载

# 缓存优点

  • 减少冗余的数据传输,节省宽带流量
  • 减少服务器负担,提高网站性能
  • 加快客户端加载网页的速度。

# 其他特性

  • F5,去看看文件过期了没有?请求带上 If-Modify-since,但是现在很多网站的没有这个字段
  • CTRL+F5,先删除缓存文件,再去服务器请求完整资源文件,强迫客户端强制执行首次更新拉取最新的资源,不缓存

# 总结

  • 强缓存:Cache-controlExpires
  • 协商缓存:last-modifiedeTag
  • Cache-Control:max-ege:600: 在600s后,请求这个文件才重新请求服务器
  • Expires: Expires= max-age + 请求时间,需要与 last-modified 配合
    • 过期时间前,可以从浏览器缓存取数据,无需请求

# TODO:问题

  1. HTTP 的服务器是如何缓存数据的?
  2. cache-control:max-age=1010s 后如何处理后续的缓存工作?
  3. 协商缓存是什么?
  4. 强缓存是什么?是怎么判断本地有缓存的?
  5. Chrome 勾选了 Disable Cache,禁用缓存
  • 顺序: 强缓存(Cache-ControlExpires) ——> 协商缓存(last-modifiedETag)。 直接进入协商缓存
  1. Chrome 取消勾选了 Disable Cache
  • 顺序: 强缓存(Cache-ControlExpires) ——> 协商缓存(last-modifiedETag)
  • 此时直接从memorydisk 中读取存储的缓存