kingwbs 2019-06-20
分为强缓存和协商缓存
浏览器在加载资源的时候,会根据这个资源的http header判断它是否命中强缓存,如果命中,就直接从缓存中读取资源,不会发请求到服务器。
当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端一句资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回,告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源。
当协商缓存也没有命中的时候,浏览器直接从服务器加载资源数据。
强缓存是利用Expires或者Cache-Control这两个http response header实现的,它们都用来表示客户端缓存的有效期,请求响应返回的状态为200
Expire:Thu, 31 Dec 2037 23:55:55 GMT
1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在response的header加上Expires的header;
2)浏览器再请求这个资源时,先从缓存中寻找,找到这个资源后,拿出它的Expires跟当前的请求时间比较,如果请求时间在Expire指定的时间之前,就能命中缓存;
3)如果缓存没有命中,浏览器直接从服务器加载资源时,Expire Header在重新加载的时候会被更新
缺点
Exipires是较老的强缓存管理header,由于它是服务器返回的一个绝对时间,在服务器时间与客户端时间相差较大的时候,缓存管理容易出现问题,比如随意修改一下客户端时间就能影响缓存命中的结果。
Cache-Control: max-age = 315360000
1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在response的header加上Cache-Control的header;
2)浏览器在接收到这个资源后,会把这个资源连同所有response header一起缓存下来
3)浏览器再请求这个资源时,先从缓存中寻找,找到这个资源后,根据它第一次的请求时间和Cache-Control设定的有效期,计算出一个资源过期时间,再拿这个过期时间跟当前的请求时间比较,如果请求时间再过期时间之前,就能命中缓存;
4)如果缓存没有命中,浏览器直接从服务器加载资源时,Cache-Control Header 在重新加载的时候会被更新。
前者描述的是绝对时间,后者是相对时间
可以只启用一个,也可以同时启用,同时存在时,Cache-Control优先级高于Expire
1)通过代码方式,在web服务器返回的相应中添加Expires和Cache-Control Header;
2)通过配置web服务器的方式,让web服务器在响应资源的时候统一添加Expires和Cache-Control Header
请求响应返回的状态为304并且会显示一个Not Modified的字符串,协商缓存是利用的是Last-Modified,If-Modified-since和ETag,If-None-Match这两对Header来管理的
Last-Modified: Tue, 12 Jan 2016 03:08:53 GMT
If-Modified-Since: Tue, 12 Jan 2016 03:08:53 GMT
1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间;
2)浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值;
3)服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header中不会再添加Last-Modified的header,因为既然资源没有变化,那么Last-Modified也就不会改变,这是服务器返回304时的response header;
4)浏览器收到304的响应后,就会从缓存中加载资源;
5)如果协商缓存没有命中,浏览器直接从服务器加载资源时,Last-Modified Header在重新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值;
缺点:
有时候服务器上资源其实有变化,但是最后修改时间却没有变化,而这种问题又很不容易被定位出来,而当这种情况出现的时候,就会影响协商缓存的可靠性
ETag: "17fd8-5291a5f96fd20"
1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上ETag的header,这个header是服务器根据当前请求的资源生成的一个唯一标识,这个唯一标识是一个字符串,只要资源有变化这个串就不同,跟最后修改时间没有关系,所以能很好的补充Last-Modified的问题;
2)浏览器再次跟服务器请求这个资源时,在request的header上加上If-None-Match的header,这个header的值就是上一次请求时返回的ETag的值;
3)服务器再次收到资源请求时,再根据资源生成一个新的ETag,与浏览器传过来If-None-Match比较,如果这两个值相同就说明资源没有变化,否则就是有变化;如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化
4)浏览器收到304的响应后,就会从缓存中加载资源。
注意的问题
分布式系统里多台机器间文件的Last-Modified必须保持一致,以免负载均衡到不同机器导致比对失败;
分布式系统尽量关闭掉ETag(每台机器生成的ETag都会不一样);