浏览器的强缓存与协商缓存

浏览器缓存是实现HTTP协议中缓存的一种方式,除此之外还有CDN缓存、反向代理缓存和负载均衡缓存等,此处的浏览器缓存为Web缓存。

注意

本文部分内容内容有误,请详细查看此文:
https://mp.weixin.qq.com/s/23WJXJFGJ-iMP6x-lFQ8og

缓存的分类及区别

浏览器的缓存分为强缓存协商缓存,在一定情况下强缓存生效,在一定情况下采用协商缓存策略,具体流程参考下图:

PS: 浏览器器的缓存目标不在本文之中

整体流程图

浏览器缓存机制.png

我把前面浏览器缓存的流程进行了步骤划分,从①~⑧在下面依次说明:

步骤分析

用户发起一个HTTP请求,例如进入 https://blog.3gxk.net,之后会因为script,img等标签的缘故会多次发起请求,在这些请求中就会进入下面的步骤。

浏览器会把这些请求给拦截下来,进行缓存判断,如果缓存有效的话就无需发起真实的请求。

判断强缓存是否生效,如果是第一次发起请求自然就没有缓存一说,强缓存的命中条件必须进行过首次请求。在第一次请求后响应头中会带有Expires或者Cache-Control字段,或者两者都存在,同时存在时优先级Cache-Control>Expires

  • Expires: HTTP/1.0中的控制字段,其值为该资源的过期时间
  • Cache-Control: HTTP/1.1中的控制字段,其值有多个选项:

    • public: 表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容
    • private:浏览器默认值,表明响应只能被单个用户缓存,不能作为共享缓存
    • no-cache:在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证(即直接进行协商缓存判断)。
    • no-store:缓存不应存储有关客户端请求或服务器响应的任何内容(即不进行任何缓存,包括强缓存和协商缓存)。
    • max-age=:设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。时间是相对于请求的时间。
    • 更多字段查看:Cache-Control - HTTP|MDN

前四项值可以与第五项的值并列使用,如Cache-Control:public, max-age=600表示缓存所有内容并且在600秒(相对于请求时间)之后过期。

privatepublic仅存在HTTP响应头中,其余字段可在请求头也可在响应头中。

所以在Cache-Control的值为no-cache或者缓存时间失效时才会进入协商缓存的判断。

如果强缓存的判断生效,例如Cache-Control字段中max-age属性值代表的时间没有到期,或者Expires字段表示的时间没有到期时会进入该步骤,此时浏览器不会真实的发送请求,只会在缓存的获取数据。不过HTTP状态码依然是200

⑤⑥⑦⑧

如果强缓存没有生效,或者主动进入协商缓存步骤,则此时浏览器会携带一些控制字段发送真实的请求。控制字段也是两组方式:Last-Modified / If-Modified-SinceEtag / If-None-Match,优先级Etag / If-None-Match>Last-Modified / If-Modified-Since

这两对控制字段,If-Modified-SinceIf-None-Match在HTTP请求头中,Last-ModifiedEtag存在HTTP响应头。

  • Last-Modified / If-Modified-Since:两个字段的值都为时间,第一次请求时服务器会返回是该资源最后一次修改的时间,待浏览器下次请求时携带该时间,服务器进行检测,如果相同则服务器返回HTTP 304,返回内容为空,此时浏览器采用本地缓存数据。如果时间不同则表示该资源有更新,此时服务器返回HTTP 200,同时返回新的资源内容。
  • Etag / If-None-Match:两个字段是字符串,由服务器生成的唯一标识,大多数情况下是该资源的摘要(如果文件很大,如何快速计算摘要又是另一门学问了),浏览器在下次请求时依然携带该摘要,服务器进行计算后判断内容是否有更新,再决定返回什么HTTP状态码(和上述相同)。

至于为何会有两种方式来进行协商缓存,是因为通过时间判断不精确,它的精度为秒级。而 Etag 需要计算,消耗会更大,所以他们各有利弊吧。

结语

文章为个人理解,如有和事实不符请在留言区指出,谢谢。

参考资料:

彻底理解浏览器的缓存机制

Cache-Control - HTTP|MDN

0 评论