浏览器缓存

缓存可以分为服务端的缓存和浏览器的缓存,对于前端来说,能控制的就是浏览器的缓存,所以着重讲一下浏览器的缓存。

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

强缓存

协议缓存

强缓存:

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

  • expires
  • Cache-Control

expires:

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

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

由于 expires 是采用客户端时间去和缓存失效时间做对比,但客户端时间是可以做修改的,如果客户端时间和服务端时间并不同步,就会导致强缓存失效,或者时效变少。

所以,在 HTTP/1.1 中增加了 cache-control 头。

cache-control:

cache-control 常见值为:

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

如果expires 和 cache-control 都被设置了,但是 cache-control 优先级高,所以该资源会在 2592000 秒(也就是 30 天)后失效。

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

Memory Cache & Disk Cache

network查看浏览器请求的时候:

from memory cache(内存缓存)和 from disk cache(磁盘缓存)

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

读取 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

上面这个例子可以看到:

  • 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 文件引入的文件名发生变化时,才会去下载最新的资源文件,否则就一直使用缓存
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页