享学课堂特邀作者:老顾
转载请声明出处!
上一篇老顾介绍了CDN相关的知识,最后留了一下问题,就是缓存控制,今天老顾介绍一下如何控制缓存?
Cache Control响应头
首先我们先来看一下Cache Control这个概念,我们先看一下访问一个网站,观察一下响应头部
我们发现cache-control的值为max-age=31536000,从字面上面就能够猜出它的含义,就是服务端告诉客户端此信息可不可以缓存,以什么样的策略进行缓存;cache-control有哪些类型的值呢?
1、private:客户端可以缓存
2、public:客户端和代理服务器可以缓存
小伙伴们会疑惑什么是代理服务器可以缓存?我们用户电脑访问web站点之间,很有可能会经过类似 nginx的反向代理服务器,也有可能会经过我们 正向代理的服务器,也有可能会经过 CDN网络;
因此我们中间层的服务节点,发现cache-control的值为private时,就认可只有发起请求的客户端能够缓存,作为代理服务节点是不能够缓存的。如为public时,代理服务器也可以缓存。
3、max-age:缓存的内容将在xxx秒后失效
这个意思就是在客户端收到信息后,信息会缓存xxx秒;过了xxx秒客户端必须重新获取信息。
4、no-store:不缓存请求的任何返回内容
不缓存请求返回的任何内容
5、no-cache:强制向服务器端再验证一次
no-cache和no-store的区别就是, no-cache会缓存请求返回的内容,而 no-store不缓存;但no-cache时,在 下次用缓存的内容时,需要向服务器验证一下,缓存到底能不能用。
逻辑流程图
流程图中,服务根据自身的业务,设置cache-control的值为:no-store、no-cache等,如:
Cache-Control: public, max-age=86400
在逻辑流程图中,有一个环节就是重新验证,就是验证缓存内容是否有效,那验证逻辑是什么,怎么验证?
ETag验证
ETag:资源唯一标识
一般会把请求的内容做md5加密,返回唯一的标识;会把ETag的值一起返回给浏览器;浏览器会把ETag存储下来。
Etag: "5d8c72a5edda83343d6aere"
下一次请求时将Etag一并带过去给服务器,服务器只需要比较客户端传来的ETag跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。
如果服务器 发现ETag匹配不上,那么直接以 常规GET 200状态码形式将新的资源(当然也包括了新的ETag)发给客户端;如果 ETag是一致的,则直接 返回304状态码客户端直接使 用本地缓存即可。
那么客户端是如何把标记在资源上的ETag传回给服务器的呢?请求报文中有两个首部字段可以带上ETag值:
1、If-None-Match: ETag-value
If-None-Match: "5d8c72a5edda83343d6aere" 告诉服务端如果ETag没匹配上需要重发资源数据,否则直接回送304和响应报头即可。
当前各浏览器均是使用的该请求首部来向服务器传递保存的ETag值。
2、If-Match: ETag-value
告诉服务器如果没有匹配到ETag,或者收到了“*”值而当前并没有该资源实体,则应当返回412(Precondition Failed) 状态码给客户端。否则服务器直接忽略该字段。
需要注意的是,如果资源是走分布式服务器(比如CDN)存储的情况,需要这些服务器上计算ETag唯一值的算法保持一致,才不会导致明明同一个文件,在服务器A和服务器B上生成的ETag却不一样。
ETag优点:
1、可以更加精确的判断资源是否被修改,可以识别一秒内多次修改的情况。
2、不存在版本问题,每次请求都会服务器进行校验。
缺点:
1、计算ETag值需要性能损耗。
2、分布式服务器存储的情况下,计算ETag的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时发现ETag不匹配的情况。
Last-Modified验证
服务器将资源传递给客户端时,会将资源最后更改的时间以“Last-Modified: GMT”的形式加在实体首部上一起返回给客户端。
Last-Modified: Sun, 28 Apr 2019 02:23:05 GMT
客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求头中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回*304*状态码,内容为空。
如果两个时间不一致,则服务器会发回该资源并返回*200*状态码,和第一次请求时类似。这样保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
也类似ETag,客户端请求报文头,两种参数
1、If-Modified-Since: Last-Modified-value
If-Modified-Since: Sun, 28 Apr 2019 02:23:05 GMT
该请求首部告诉服务器如果客户端传来的最后修改时间与服务器上的一致,则直接回送304 和响应报头即可。
当前各浏览器均是使用的该请求参数来向服务器传递保存的 Last-Modified 值。
2、If-Unmodified-Since: Last-Modified-value
该值告诉服务器,若 Last-Modified没有匹配上(资源在服务端的最后更新时间改变了),则应当返回412(Precondition Failed) 状态码给客户端。
Last-Modified 存在一个问题,如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,但修改时间变化了,会导致Last-Modified时间匹配不上而返回了整个实体给客户端(跟客户端缓存里有个一模一样的资源);就是错误的判断内容改变了。
请求流程图
上面的图就是总结了一下之前所讲的,比较容易理解,不理解回头重新看。
浏览器刷新方式
1、在URI输入栏中输入然后回车
看cache-control对应的max-age是否有效,根据上面的流程图,进入协商机制
2、F5/点击工具栏中的刷新按钮/右键菜单重新加载
去掉max-age或设置max-age=0,进入上面的流程图,进入协商机制
3、Ctl+F5/commond+shift+R
去掉cache-control和协商头,不管有没有缓存,强制刷新,都要到Server服务器上面获取数据,返回200状态码
协商机制再次说明:比较ETag和Last-Modified到服务端,若服务端一致,没有变化,则返回状态码304,不返回数据;否则返回状态码200,返回数据。
动态数据
根据上面的知识,我们去取动态数据时(如:ajax动态请求),服务端就可以利用上面的规则控制客户端不要缓存,设置cache-control为max-age=0;且不设置ETag和Last-Modified就可以达到不缓存;反之如果要缓存数据,设置相关的值就行了。
CDN自定义缓存策略
1、可自定义目录的过期时间
不管源服务器的缓存过期是什么规则,CDN服务 自定义目录过期时间,假如1个小时,那1个小时后, CDN设置的缓存目录里面的内容会过期,会再 去源服务器那边获取新的信息(简称回源)。
2、可自定义后缀名过期时间
可根据后缀名设置缓存策略,如:html、js、css等
3、可自定义对应权重
如设置了后缀名的权重比目录过期高,那么就遵循后缀名过期规则
4、可通过界面或API强制CDN对应的目录进行刷新(不一定会成功)
总结
现在的CDN产品已经比较成熟,有后台控制台管理进行缓存的配置,如果需要程序控制相关的缓存过期规则,可以用上面介绍的知识点配合使用。今天老顾就介绍到这里,谢谢!!!
你的赞和关注是我继续创作的动力~