浏览器 & HTTP 缓存策略

缓存策略

浏览器的缓存策略是依靠 HTTP Header 来实现的,共分为两种:web

  • 强缓存
  • 协商缓存

强缓存

强缓存是指在缓存期间,请求不会发送到服务器,浏览器直接返回缓存结果,须要设置 Header:算法

  • expires
  • Cache-Control

expires

expires: Wed, 10 Oct 2020 09:51:00 GMT

expires 是 HTTP/1.0 中用于控制网页缓存的字段,其值表明服务器返回该请求结果的缓存到期时间,也就是说,再次发起一样的请求时,若是客户端时间小于 Expires 的值,浏览器直接返回缓存结果。chrome

因为 expires 是采用客户端时间去和缓存失效时间作对比,但客户端时间是能够作修改的,若是客户端时间和服务端时间并不一样步,就会致使强缓存失效,或者时效变少。浏览器

因此,在 HTTP/1.1 中增长了 cache-control 头。缓存

cache-control

cache-control 常见值为:服务器

  • public:全部内容都将被缓存(客户端和代理服务器均可缓存)
  • private:全部内容只有客户端能够缓存,默认为 private
  • no-cache:客户端缓存内容,可是否使用缓存须要通过协商缓存来决定
  • no-store:全部内容都不会被缓存
  • max-age=xxx:缓存内容将在 xxx 秒以后失效

咱们来看个例子:
image.png网络

这个例子中,expires 和 cache-control 都被设置了,可是 cache-control 优先级高,因此该资源会在 2592000 秒(也就是 30 天)后失效。学习

咱们能够得出 2 个结论:this

  1. 当 expires 和 cache-control 同时存在时,只有 cache-control 生效。
  2. 在某些不支持 HTTP/1.1 的环境下,expires 就会发挥用处,现阶段它的存在只是为了兼容性

Memory Cache & Disk Cache

image.png

当咱们 F12 查看浏览器网络请求的时候,确定看到过这样的信息,from memory cache(内存缓存)和 from disk cache(磁盘缓存)。spa

当请求命中强缓存时,浏览器就会从内存或者磁盘中将缓存的资源返回来,请求不会到达服务器。

那么,哪些资源缓存在 memory,哪些缓存在 disk 呢?

关于 memory cache 和 disk cache,Chrome 官方有这么一段描述:

Caching
Chrome employs two caches — an on-disk cache and a very fast in-memory cache. The lifetime of an in-memory cache is attached to the lifetime of a render process, which roughly corresponds to a tab. Requests that are answered from the in-memory cache are invisible to the web request API. If a request handler changes its behavior (for example, the behavior according to which requests are blocked), a simple page refresh might not respect this changed behavior. To make sure the behavior change goes through, call handlerBehaviorChanged()to flush the in-memory cache. But don't do it often; flushing the cache is a very expensive operation. You don't need to call handlerBehaviorChanged()after registering or unregistering an event listener.

以上引用自 Chrome API

读取 memory 中的缓存资源,确定要比读取 disk 中的更快,可是 memory 中的缓存,会随着进程的释放而释放,也就是说,一旦咱们关闭 Tab 标签,memory 中的缓存也就没有了。

那么哪些资源会被缓存到 memory,哪些会缓存到 disk 中呢?关于这点我也没有找到定论,大多数的观点以下,供你们参考:

  • 大文件,优先缓存至 disk,小文件优先缓存至 memory
  • 当内存占用率高的状况下,优先缓存至 disk

协商缓存

若是请求没有命中强缓存,或者强缓存失效后,就须要向服务器发起请求,验证资源是否有更新,这个过程叫作协商缓存。

当浏览器发起请求验证资源时,若是资源没有改变,那么服务器返回 304 状态码,而且更新浏览器缓存有效期;若是资源发生改变,那么服务器返回 200 状态码,而且返回相应资源,更新浏览器缓存有效期。

那么服务器如何肯定资源有没有更新呢,这里就要用到如下 2 组 HTTP 头。

last-modified & if-modified-since

last-modified 表示文件的最后修改日期,由服务器添加到 Response Header 中;if-modified-since 由浏览器添加到 Request Header 中,是上一次该资源的 last-modified 值。

服务器收到请求后,会将 if-modified-since 和服务器上该文件的修改时间戳进行比对,若是超过了缓存时间,那么则返回最新的资源,200 状态码,若是还在缓存有效期内,则返回 304 状态码。

image.png
image.png

上面这个例子能够看到:

  • Request Header 中 if-modified-since: Fri, 20 Dec 2019 12:44:01 GMT
  • Response Header 中 last-modified: Fri, 20 Dec 2019 12:44:01 GMT

这里服务器将 if-modified-since 的时间和服务器上文件的修改时间作比对,发现仍在缓存时间有效期内,因此直接返回 304 状态码,并不返回文件资源,由浏览器提供缓存好的资源。

可是 last-modified 也有它的缺点:

  • 若是服务器上的文件被打开过,及时没有修改,它的修改时间戳也会改变,就会致使 last-modified / if-modified-since 失效,服务器再次返回一样的资源
  • last-modified / if-modified-since 是以秒为单位,若是在秒之内文件发生了修改,那么根据这组 Header 头服务器会认为文件没有修改,依然命中协商缓存,返回老的资源

由于以上这些问题,因而在 HTTP/1.1 出现了 etag / if-none-match。

etag & if-none-match

etag 相似于文件指纹,能够对文件内容作摘要算法,好比 md5,生成的值做为 etag 的值,由服务器添加到 Response Header 中,浏览器再次请求该资源时,会在 Request Header 中添加 if-none-match 头,值为上次 etag 的值,服务器收到请求后,会对请求资源再次作相同的摘要算法,和 if-none-match 值进行比对,若是不同,说明资源更新了,返回 200 以及更新后的资源文件,若是相同,说明文件没有被修改,则返回 304,由浏览器返回缓存资源。

总结来讲,last-modified / if-modified-sice 和 etag / if-none-match,就是将服务器返回的某一个值,由浏览器在发送请求的时候带回去,服务器拿到值后和本地文件的某个属性进行判断,来决定是否返回新的资源,仍是由浏览器返回缓存资源,这个过程,就叫作协商缓存。

相似于 expires 和 cache-control,etag / if-none-match 的优先级要比 last-modified / if-modified-since 高。

若是什么缓存策略都没有设置,那么浏览器会采用一个启发式的算法,一般会读取 Response Header 中的 date 头,减去 last-modified 值的 10% 做为缓存时间。

总体流程图

image.png

实际场景

学习了上面的缓存策略,在实际场景中咱们该如何应用呢?

频繁变更的资源

  1. 彻底不缓存,cache-control: no-store
  2. 协商缓存,cache-control: no-cache,使浏览器每次请求都会走服务器,而后配合 etag 或者 last-modified 来验证资源是否有效,这样对比彻底不缓存来讲,虽然没法减小 HTTP 请求到达服务器的次数,可是能够显著减小响应数据的大小

文件

  1. HTML 文件不设缓存
  2. CSS、JS以及图片等文件资源,能够设置一个较长的缓存有效期,好比一年,cache-control: max-age=31536000,只有当 HTML 文件引入的文件名发生变化时,才会去下载最新的资源文件,不然就一直使用缓存
相关文章
相关标签/搜索