一、缓存类型
1、缓存类型分为强缓存和协商缓存
- 强缓存:在用户请求资源时,如果命中强缓存,则不向服务器请求,而直接从本地获取资源。我们可以看到200状态码,并提示from disk cache或from memory cache。
- 协商缓存: 在用户请求资源时,浏览器直接则向服务器发送请求,服务器根据 request header 来判断是否命中协商缓存,如果命中,则返回304和新的response header,使用本地资源;否则,返回新的资源。
2、区别
- 共同点:两者命中后都是从本地读取资源。
- 不同点: 强缓存很强势,是没有向服务器发出请求的; 而协商缓存必须要向服务器发一个请求来协商。
二、强缓存header
强缓存是利用http的响应头中的Expires字段和Cache-Control两个字段来控制,用来表示使用缓存的有效时间。
1、Expires
Expires是http1.0规范的,表示缓存的过期时间。 如某个资源的response heade中的字段: Expires: Fri, 18 Aug 2017 07:57:17 GMT
。 表示当浏览器再次加载这个资源时,如果时间没有超过,就命中强缓存,使用内存中缓存的资源。
之所以浏览器在再次加载时可以判断出时间是否超过,是因为浏览器在缓存资源时,不仅缓存了资源,还缓存了response header相关的内容,比如这里Expires字段。
缺点:由于不能保证服务器和用户端的绝对时间保持一致,所以缓存有时可能会出现混乱的情况, 在HTTP1.1版本中开始使用Cache-Control的方法进行缓存。
2、Cache-Cntrol
Cache-Control是http1.1规范的,同样表示缓存的过期时间。 其中的max-age是作为判断是否过期的主要判据,它是一个相对时间,单位为s。 如知乎上的某一张图片的response header中的字段:cache-control: public, max-age=31536000
。 public代表了这张图片是可以被任何用户缓存的,包括代理服务器等; 而max-age是表示在31536000s(一年)内,如果再次请求就使用本地资源。Cache-Control除了max-age的使用之外,还有几个比较重要的字段:
- no-cache: 不优先使用本地缓存,而是使用协商缓存。注意: 这里并不是说一定不适用本地缓存的资源,而是需要先协商一下,如果命中,还是会使用本地缓存的。
- no-store:一定不使用本地缓存,每次用户请求资源,都会下载得到服务器发来的最新的资源。
- public:资源可以被任何用户缓存,包括所有普通用户和代理服务器。
- private:只能被当前的特定用户缓存,其他用户无法缓存。 一般是说代理服务器不能缓存。
3、Expires、Cache-Control比较
相同点: 两者都是强缓存。
不同点:
- Expires是http1.0规定的,而Cache-Control是http1.1规定的。
- Expires的过期时间采用的是绝对时间,容易造成差错; 而Cache-Control的过期时间采用的时相对时间,在缓存上不会出现问题。
- 两者可以同时存在于一次请求中,但是不会同时在一次请求中起作用。 在HTTP1.0的环境下,Cache-Control不起作用,Expires起作用; 在HTTP1.1的环境之下, Expires不起作用,而Cache-Control起作用。当前一般都是http1.1的情况,所以Expires是作为一种向下兼容的形式而存在的。
- Cache-Control的选择更多,功能更为强大,推荐使用。 Expires作为强缓存,功能单一,不推荐使用。
三、协商缓存header
协商缓存一般是使用if-modified-since
/last-modified
和 f-none-match
/etag
由服务器来决定浏览器缓存的资源是否可以使用。
1、if-modified-since/last-modified
- 在用户请求资源之后,服务器会返回这个资源,并且在response header中返回一个
last-modifed
字段,这时浏览器就会缓存这个资源以及最后的修改时间, 可以是:last-modified: Fri, 18 Aug 2017 07:27:24 GMT
。 - 接着,当用户再次请求相同的资源时,需要在请求头中添加
if-modified-since
字段,这个字段的值就是之前存储的last-modifed
的值,服务器得到 if-modified 值之后,会和资源最近的修改时间作比较,如果命中,则返回304,让浏览器使用缓存的资源;否则,返回一个最新的资源并且在last-modified
修改为最近的资源修改时间。
- 在用户请求资源之后,服务器会返回这个资源,并且在response header中返回一个
2、if-none-match/etag
- 在用户请求到资源之后,会返回这个资源,并且在response heade 中返回一个
etag
字段,即entity tag
,这个字段的值是一个字符串,唯一的标识了这个资源,只要资源发生了变化,这个etag值就会发生变化。 - 当用户再次请求资源时,会在request header中携带
if-none-match
字段,其值为上次缓存的etag
值,如果命中,则返回304,使用缓存资源;否则,服务器返回最新的资源。
- 在用户请求到资源之后,会返回这个资源,并且在response heade 中返回一个
3、两种协商缓存机制的比较
相同点: 都是为了协商缓存。
不同点:
- 在精度上,Etag优于last-modified。 如果一个文件在1s内改变了很多次,通过etag是可以判断出来并返回最新的资源的,但是last-modifed的精度只能到s,是无法返回最新资源的,准确地说,UNIX记录只能精确到s。
- 在准确率上,Etag优于last-modified。有些文件可能整体copy等,只是在时间上发生了变化,而内容上并没有发生变化(etag变化,last-modified不变),如果使用last-modified,那么就会返回最新的资源,实际上这是不需要的。
- 在性能上,last-modified优于Etag。因为last-modified只需要记录时间,而etag需要重新由服务器生成一个hash值,所以在性能上etag略差。
在优先级上,Etag优于last-modified。 也就是说,etag和last-modified是可以同时使用的,但是到服务器端,会优先判断etag,如果相同,直接返回304;如果不同,就继续比较last-modified,然后再决定是否返回新的资源。
四、浏览器缓存过程
- 浏览器第一次加载资源,服务器返回200, 浏览器将资源下载下来,把资源和response header相关内容一并缓存。
- 下一次加载时,首先比较cache-control,如果没有超过时间,则命中强缓存,不发送请求,直接读取本地文件(如果不支持http1.1,则使用expires来判断);如果时间已经过期,则发送带有
if-none-match
和if-modified-since
的请求头。
- 服务器接受到请求之后,首先判断
etag
是否和服务器上文件的etag
一致,如果一致,则命中协商缓存,返回304;如果不一致,返回新的资源并带上新的etag值返回200。
如果请求中没有
etag
值,则比较发送来的if-modified-since
值,如果命中,则返回304,;否则,返回新的资源带上新的last-modified
的值并返回状态码200。
五、用户行为与缓存类型
- 地址栏访问,链接跳转是正常用户行为,将会触发浏览器缓存机制;
- F5刷新,浏览器会设置
max-age=0
,跳过强缓存判断,进行协商缓存判断; - ctrl+F5刷新,跳过强缓存和协商缓存,直接从服务器拉取资源。