浏览器缓存机制

基本流程

  1. 加载资源时,首先根据上次资源响应 Header 中的ExpiresCache-Control判断是否命中强缓存,如果命中则直接从缓存中取,不会发送资源请求到服务器
  2. 如果没有命中强缓存,则服务端根据Last-Modified/If-Modified-SinceETag/If-None-Match验证是否命中协商缓存,如果命中则返回 304 响应,不会返回资源数据
  3. 如果没有命中协商缓存,则服务端返回资源数据

比较

相同点:不论是哪种缓存,都是从本地加载资源,服务端不会返回资源数据
不同点:强缓存不会产生请求,协商缓存会产生请求

强缓存

Expires表示缓存到期时间,是一个绝对时间,形如Thu, 10 Oct 2017 01:47:03 GMT,它存在于资源的响应头中。该字段出现于 HTTP/1.0 规范中。
Cache-Control表示缓存到期的相对时间,以下是一些常用字段值

  1. max-age=86400,表示 24 小时后失效
  2. must-revalidate,如果超过了 max-age 设置的时间,必须发送请求验证资源是否还有效
  3. no-cache,依然缓存资源,但是否使用该资源,由后续的对比决定
  4. no-store,真正意义上的“不要缓存”
  5. public,内容可以被客户端和代理缓存(如 CDN)
  6. private,内容只能被客户端缓存,代理不能缓存,默认值。

这些字段可以被混合使用,字段间关系如下
cache.webp
Cache-Control 的优先级高于 Expires,出于兼容性考虑,两个字段常常会被同时设置

协商缓存

如果没有强缓存相关字段,或者强缓存判定资源失效时,进入协商缓存阶段机制(也就是说,强缓存优先级高于协商缓存)。

Last-Modified & If-Modified-Since

第一次请求资源时,资源响应头通过Last-Modified字段告知客户端资源的修改时间,客户端会记录下该时间,在下次请求时,会将该时间写入资源请求头的If-Modified-Since字段。服务端收到该请求后,将If-Modified-Since中的时间与资源的上次修改时间进行对比,两个值一致时,返回 304 响应,否则正常返回新的资源。

ETag & If-None-Match

该机制的运行流程和Last-Modified & If-Modified-Since类似,只不过将资源修改时间改成了资源内容的 hash,该 hash 在资源响应头的 ETag 中体现,在之后的资源请求头的 If-None-Match 中传回,服务器进行对比,如果一致则返回 304,否则正常返回资源。
ETag 的优先级要高于 Last-Modified

Memory Cache vs Disk Cache

Chrome DevTools 有时会观察到(from memory cache),有时则是(from disk cache),可以通过以下操作复现

  1. 资源设置为Cache-Control: max-age=86400,首次打开页面时,响应 200,返回资源
  2. 刷新页面,显示 from memory cache
  3. 关闭页面,重新打开,显示 from disk cache

此外,还可以观察到一个现象,from memory cache 时,耗时很短,往往是 0ms;而 from disk cache 时,往往需要消耗几毫秒的时间。说明确实是前者从内存里读,后者从硬盘里读。

no-cache vs no-store

用下面的场景进行说明。假设在 HTML 中,同步地请求同一个资源两次(按顺序写两遍),之后异步地再请求一次。

  1. 当资源被设置为 no-cache 时,该资源只被请求了一次,说明 no-cache 的语义实际上是下次打开页面时,要重新请求资源,但在当前页面上的请求,有缓存的时候还是可以放心用的
  2. 资源被设置为 no-store 时,该资源被请求三次,说明 no-store 无论无何都会发送请求(猜测,和名字体现出来的一样,no-store 根本就没把资源存储下来)

1338 Words

2018-05-06 17:21 +0800

comments powered by Disqus