前台经常会被问HTTP缓存,那么HTTP缓存的发展理解多少呢?为什么会出现各种不同的缓存字段?本篇文章会从缓存的类型开始,逐一说明缓存相关的HTTP字段,相信读完会对以上的问题有所理解。注意,以下讲解只针对HTTP缓存的情况。
缓存分强缓存与协商缓存两种,简单来讲的话,强缓存期间请求不会到达服务器,即在缓存有效期内命中缓存,浏览器会使用本地缓存;协商缓存是在没有命中缓存或者强缓存失效的情况下,与服务器进行协商来决定返回的请求资源。大概的流程如下:
简略的请求流程Expires与Cache-Control。Expires字段,用于表示当前资源过期的时间。该字段形容的是一个绝对时间,由服务器返回,用户端本地只需超过这个时间则缓存失效。Expires: Sun, 24 May 2020 07:41:19 GMT。Expires是最初的缓存控制字段,为它开始web应用减少了很多不必要的带宽白费,可以指定少量不常升级的文件形成缓存。但开发者们很快发现了新的问题,Expires依赖用户端的时间进行判断,用户端修改了时间会影响缓存的有效性,这在某些情况下会比较致命,比方一个重要文件,理应在今天过期,但因为用户端时间修改成了去年,造成了缓存没有刷新,这就会很尴尬。为理解决这个问题,在HTTP/1.1中加入了Cache-Control字段来控制缓存,以满足更多的需求,配置如下。需要注意的是,该字段优先级高于Expires。public 可以被所有客户缓存,这里包括浏览器、代理商服务器、CDN等。private 只能被浏览器缓存,不允许被其它如代理商服务器缓存。no-store 不缓存no-cache 先缓存本地,但命中缓存后必需与服务器验证资源新鲜度才能使用。这里注意,不要被名字误导成不缓存了。max-age 用相对时间来表示缓存有效期,表示缓存将在XX秒后失效。示例Cache-Control: max-age=315360000
Cache-Control设置假如在缓存有效期内命中缓存,则使用强缓存,但是,假如命中缓存时缓存失效了怎样办?这个时候就要进入协商缓存流程了。进入协商缓存的条件不单是缓存失效,还包含以下三种情况:
Cache-Control与ExpiresCache-Control:max-age与Expires导致的缓存失效Cache-Control: no-cache当存在以上三种情况时,第二次请求服务器就会进入协商缓存流程。协商缓存过程也涉及了HTTP状态码的改变,当请求发现服务器存在缓存或者且缓存没有升级时,升级缓存时间并返回304 Not Modified;假如缓存失效,则服务器会把最新资源的完整版返回给浏览器,状态码为200 OK。看到这里大概就已经明白了协商缓存的过程,但细想一下还有少量没有说清楚的地方,服务器是如何校验缓存的新鲜度的呢?
当浏览器初次请求服务器资源时,服务器会将请求资源的最新修改时间Last-Modified: Tue, 07 Apr 2020 06:24:10 GMT通过响应头部返回给浏览器,浏览器在下次发起同一资源请求时会带上该信息,通过在请求头部设置If-Modified-Since: Tue, 07 Apr 2020 06:24:10 GMT,服务器会比对Last-Modified/If-Modified-Since假如服务器的资源有升级,则将最新的资源返回给浏览器,并升级响应头中的Last-Modified值,此时响应状态码为200 OK;假如服务器资源没有升级(两者时间一致),浏览器直接使用缓存就可,此时响应状态码为304 Not Modified。
理论上通过比对资源的最新升级时间就可判断缓存能否有效,但实际操作中还是会遇到问题,比方资源文件在一秒内屡次修改、资源经过编辑但没有发生实质内容修改的情况,这些问题表明以Last-Modified来判断还不够准确,我们需要引入ETag字段。大体流程上ETag与Last-Modified的校验差不多,区别在于ETag不使用文件修改时间,而是使用文件内容摘要算出来的hash值进行判断,只需资源实质发生修改就会刷新hash值。服务器通过响应头中的ETag告知浏览器文件缓存信息,那么浏览器是如何把ETag的信息发送给服务器的呢?有以下两种形式:
If-None-Match: ETag value:通知服务器,假如没有匹配上,则需要重新发送资源;假如匹配上则直接返回304 Not Modified。一般浏览器使用该字段来回传ETag值。If-Match: ETag value:通知服务器,假如没有匹配上ETag,或者当前ETag: *但没有资源实体,则返回412 Precondition Failed;假如匹配上了,则服务器不做任何解决。采用分布式服务器(如CDN)时,需要保证各服务器上的ETag算法一致,才不会出现A服务器与B服务器同一文件不同ETag值的出现。
在整理资料的时候还发现了这个字段,该字段是HTTP/1.0的遗留之物,按辈分讲与Expires平齐。该字段用来定义能否需要缓存,可选值只有Pragma: no-cache,这个即可以按照字面意义了解成不进行缓存,即每次都会请求服务器的资源。优先级来讲Pragma > Cache-Control > Expires,当然,现代规范还是推荐使用Cache-Control的。