缓存分为2种:
1. 强缓存: 直接从本地缓存中取资源,不会和服务器通信,返回的http状态码是200(from cache);
2. 协商缓存:通过服务器来告知是否能用本地缓存。先和服务器通信,如果返回可以使用本地缓存的指示,再从本地缓存中取(服务器不会返回被请求资源,返回的状态码是403(Not Modified));如果不可以使用本地缓存就会返回最新的资源;
浏览器发起第二次相同的请求时会先判断能不能使用强缓存,不行的话,再判断能不能使用协商缓存(如果没有设置强缓存,协商缓存也不会生效)。
一、强缓存
强缓存是由headers中的Expires和cache-control决定的,后者优先级高于前者。
Expries是http1.0提出的,表示失效时间(GMT格式),只有在这个时间之前的请求才可以用强缓存。
第一次向服务器请求一个资源后,浏览器不仅会把资源保存起来,也会保存Reponse Headers,包括其中的Expires。第二次发请求时先去缓存中寻找这个资源,取到Expires,与当前的请求时间做对比,如果在Expires之前,则从缓存中取,否则重新向服务器请求,Expires在重新加载时被更新。
cache-control可以有多个值:
cache-control: max-age=111000 -->表示自第一次收到响应后的111000ms以后可以用缓存
cache-control: no-cache -->禁止使用强缓存
cache-control: no-store -->禁止使用缓存,每次都要去服务器重新请求
cache-control: private -->只允许被终端用户的浏览器端缓存
cache-control: public -->可以被所有用户缓存,保存终端用户和CDN等代理服务器
由于Expries是个绝对时间,由于各个客户端之间有时差就会导致缓存不一致的问题,所以http 1.1提出了cache-control,是个相对时间,在第二次发请求时取到缓存中的max-age和第一次的请求时间计算出资源过期时间,与当前的请求时间对比决定是否使用缓存。
二、协商缓存
有两组headers值:Last-Modified / If-Modified-Since 和 Etag / If-None-Match,后者优先级高于前者。
第一次和第二次的同一个请求:
1. Last-Modified / If-Modified-Since
第一次请求时返回的Response Headers中用Last-Modified表示请求的资源在服务器上最新的修改时间,第二次请求时在Request Headers中用If-Modified-Since带上这个值发到服务器,服务器对比这个值和这个资源市价上的最新修改时间决定是否直接返回403还是返回资源。当返回403时,表示资源没有更新,所以浏览器缓存中的Last-Modified也就不用更新了。
但是Last-Modified的问题在于有时服务器上资源其实有变化,但是最后修改时间却没有变化,所以有了Etag / If-None-Match来管理协商缓存。
2. Etag / If-None-Match
Etag是服务器根据被请求资源生成的一个唯一标识字符串,只要资源发生变化,Etag就会变,跟资源的最新修改时间没有关系,能弥补Last-Modified的不足。与Last-Modified类似,第二次请求时请求头会带上If-None-Match标识的Etag值,区别是由于服务器每次会根据资源重新生成一个Etag,再拿它跟浏览器传过来的Etag对比,如果一致则返回403,所以由于每次Etag都会重新生成,所以浏览器缓存中的Etag也必须每次都更新。
一般Last-Modified和Etag是同时启用的,但是对于分布式系统多同机器间文件的Last-Modified必须一致,以免因为负载均衡到不同机器导致比对不一致,分布式系统尽量关闭Etag,因为每台机器生成的Etag也不一致。
另外当使用F5刷新时会跳过强缓存,当强制刷新时,强缓存和协商缓存都会跳过。其他操作行为如前进后退,地址栏回车都会按正常流程走。
浏览器默认都会缓存图片,js,css等静态文件,也可以通过待会再响应头中设置是否要启用缓存,或是通过服务器专门的配置文件统一设置Expires, Cache-control等。
a.css?v1.1 和 a_v1.1.css, 覆盖式发布 和 非覆盖式发布