浏览器缓存-强缓存vs协商缓存

一、浏览器的应答模式

浏览器与服务器之间的通行是应答模式,即浏览器发出HTTP请求,服务器响应请求。在这个过程中,浏览器如何知道是否使用缓存如何使用缓存。浏览器第一次发起请求后,会将请求结果和缓存标识存到浏览器缓存中,下一次发起请求时,会根据浏览器缓存中的缓存标识和缓存规则决定是否使用缓存。流程如下:
浏览器缓存-强缓存vs协商缓存_第1张图片
这里有两个关键点:

  • 浏览器每次发送请求都会到浏览器缓存中查询缓存结果和缓存标识
  • 浏览器每次拿到响应都会把请求结果和缓存标识放到浏览缓存中

只要再理解了缓存规则,就可以很好的掌握浏览器缓存了。我们根据是否再次向浏览器发送请求,将缓存规则分为两类:

  • 强缓存
  • 协商缓存

二、强缓存

强缓存的精髓在于设置一个缓存的过期时间,如果叫我们来设置该如何去设计?可以有两种方法:

  • 缓存到某个时间点就过期
  • 缓存可以存活多长时间

这两种方法正式HTTP协议使用的方法,因此,我们可以有两种手段实现强缓存:

  • Expires
  • Cache-Control

2.1 Expires

Expires的实现机制是:在请求的头部Expires: {到期时间}字段,当浏览器发送请求时会根据这个到期时间来决定是否使用缓存。
浏览器缓存-强缓存vs协商缓存_第2张图片
可以看到,在请求的返回体中有Expires字段,标识了这个缓存在Sun Aug 16 2020 09:18:31 GMT+0800 (GMT+08:00)这个时间后将会失效。
浏览器缓存-强缓存vs协商缓存_第3张图片
多发送几次请求,可以看到在浏览器F12 -> network中,size列,可以很容易的发现,第一次请求没有使用缓存,后面几次请求使用了浏览器缓存。
想一想,expires有什么弊端?

Expires 是 HTTP/1.0 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效

2.2 Cache-Control

因为Expires的缺陷,在HTTP/1.1后推出了Cache-Control规则(加在请求头部),这个规则主要的取值如下:

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

这个地方no-cache会带来误解,它并不是不使用缓存,而是不使用强缓存,转而使用协商缓存;no-store的意思才是不使用缓存。

浏览器缓存-强缓存vs协商缓存_第4张图片
在请求的返回体中,设置了缓存35秒后失效,而且是public。
浏览器缓存-强缓存vs协商缓存_第5张图片
在network中size一列,很明显的看出使用的是缓存。

2.2.1 no-store

no-store的意思是告诉浏览器,不使用缓存,每次都是重新请求数据,如下:
浏览器缓存-强缓存vs协商缓存_第6张图片
将cache-control设置为no-store,每次都会重新请求,不会使用缓存数据
在这里插入图片描述

2.2.2 no-cache

no-cache是不使用强缓存,转而使用协商缓存
浏览器缓存-强缓存vs协商缓存_第7张图片
配置no-cache之后再次请求返回的是304,表明是使用了协商缓存。

2.2.2 no-cache + no-store

如果同时配置了no-cache和no-store,no-store的优先级要高
浏览器缓存-强缓存vs协商缓存_第8张图片
在这里插入图片描述

2.3 Expires和Cache-Control两者对比

  • Expires 是http1.0的产物,Cache-Control是http1.1的产物
  • 两者同时存在的话,Cache-Control优先级高于Expires

2.4 强缓存流程

浏览器缓存-强缓存vs协商缓存_第9张图片
可以看到,如果是强缓存,会直接返回缓存结果,不会再向服务器发起请求。

三、协商缓存

协商缓会向服务器发起请求,但服务器会判断是直接返回304,让浏览器使用浏览器缓存,还是重新请求资源并返回200。更具服务器的判断方式,协商缓存可以分为两种:

  • Last-Modified/If-Modified-Since
  • Etag/If-None-Match

3.1 Last-Modified/If-Modified-Since

浏览器在第一次访问资源时,服务器返回资源的同时,在response header中添加 Last-Modified的header,值是这个资源在服务器上的最后修改时间,浏览器接收后缓存文件和header。
浏览器缓存-强缓存vs协商缓存_第10张图片
浏览器下一次请求这个资源,浏览器检测到有 Last-Modified这个header,于是添加If-Modified-Since这个header,值就是Last-Modified中的值;服务器再次收到这个资源请求,会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比,如果没有变化,返回304和空的响应体,直接从缓存读取,如果If-Modified-Since的时间小于服务器中这个资源的最后修改时间,说明文件有更新,于是返回新的资源文件和200
浏览器缓存-强缓存vs协商缓存_第11张图片

弊端
  • 如果本地打开缓存文件,即使没有对文件进行修改,但还是会造成 Last-Modified 被修改,服务端不能命中缓存导致发送相同的资源
  • 因为 Last-Modified 只能以秒计时,如果在不可感知的时间内修改完成文件,那么服务端会认为资源还是命中了,不会返回正确的资源

3.2 Etag/If-None-Match

为解决Last-Midified的缺陷,推出了Etag。
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,Etag就会重新生成。
浏览器缓存-强缓存vs协商缓存_第12张图片
浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到request header里的If-None-Match里,服务器只需要比较客户端传来的If-None-Match跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。
浏览器缓存-强缓存vs协商缓存_第13张图片

3.3 Etag和Last-Modified对比

  • 首先在精确度上,Etag要优于Last-Modified。
    Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。
  • 第二在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
  • 第三在优先级上,服务器校验优先考虑Etag

3.4 协商缓存流程

浏览器缓存-强缓存vs协商缓存_第14张图片

四、缓存机制

强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回304,继续使用缓存。

五、参考文章

  • 深入理解浏览器的缓存机制
  • 彻底理解浏览器的缓存机制(http缓存机制)

你可能感兴趣的:(浏览器缓存,缓存)