缓存,在高性能系统中尤为重要,一般的缓存可以分为浏览器缓存和服务器缓存,服务器缓存又可以分为分布式缓存和本地缓存,分布式缓存一般使用memcached或redis等性能良好的中间服务,本地服务像java可以使用encache或者各种数据结构.这里我们不深究服务器缓存,而是要讲讲WEB开发中常用的浏览器缓存.
由于浏览器使用的时http,所以浏览器缓存也可以叫是http缓存.首先来看看一个普通的http响应:
看到这些报头是不是头已经蒙了,不急,我们只需要理解里面几个就可以了.
1.Expires和Cache-Control:
这两个都是告诉浏览器,当前请求是不是需要去请求服务器呀!其中,Expires是http1.0的,Cache-Control是http1.1的,如果两个都同时存在,那么Cache-Control会覆盖Expires.
Cache-Control有几种取值:
no-cache:和max-age=0效果一样,就是每次都要去请求服务器.
max-age:最大有效时间,超过这个时间的请求浏览器就要向服务器请求啦!
其它的不讲了,主要理解这两个就好了.
Expires和Cache-Control不同的是,它记录的是具体的时间点,而不是时间段(不过两个的效果时一样的哈).
2.if-Modified-Since/Last-Modified:
Expires和Cache-Control是决定请求需不需要发到服务器,if-Modified-Since/Last-Modified则是决定响应需不需要从服务端获取.从上面的http报文看出来了吗,Status Code是304 Not Modified,就是表示这个请求不用我服务端返回页面信息啦!那么这个页面信息从哪里获取呢?如果你是使用Chrome的话,在地址栏输入chrome://cache,是不是可以看到很多的似曾相识的链接!?对了,这就是浏览器的缓存了.服务器返回304响应码,浏览器捕获之后就会从本地缓存里找到当前请求url对应的页面啦.
原理是这样的:假如浏览器第一次发送index.html的请求,这时候不管你Expires和Cache-Control是什么,因为浏览器本地没有缓存啊,所以必须要向我服务器请求一次.服务器接收到请求之后,会把请求的页面文件的最近修改时间放在Last-Modified报头里面返回给浏览器(这个需要服务器处理的,像Tomcat需要配置才有效,自己开发的http服务器则要自己处理哈),浏览器接收到响应报文之后,会把整个响应保存到本地缓存里,下次当浏览器再次请求index.html时候,浏览器会从缓存里拿出这个Last-Modified放到请求报文的if-Modified-Since里发送给服务器,服务器再比较这个if-Modified-Since和当前请求页面文件的最近修改时间是否一样,一样九返回304,不一样则返回最新页面,同时更新Last-Modified发回给浏览器.
3.if-not-match/Etag
if-Modified-Since/Last-Modified是记录文件的最近一次修改时间,if-not-match/Etag则是可以表示文件内容是否有修改(当然判断逻辑需要服务端自己实现咯).Etag原理和Last-Modified差不多,只是服务端返回的Etag是根据文件内容生成的标示(比如内容的md5哈).和if-Modified-Since/Last-Modified不同的是,if-not-match/Etag不受Expires(或Cache-Control)的约束,即过期不过期与我何干,反正每次我就是要去请求服务器,服务器你告诉我要不要返回九行了!
综上所述,下面我们来理理这三者的关系:
1.Expires或Cache-Control需要和if-Modified-Since/Last-Modified一起用(当然你可以不用Expires或Cache-Control,但是浏览器会为你默认配置一个no-cache哈).
2.一般的方法是,三者都用,这样的好处是:
a)先用Expries和if-Modified-Since/Last-Modified,如果不过期则可以减少服务器请求,如果过期了向服务器发出了请求,那么不怕,下面还有招.
b)服务器接收到请求后,会先判断if-Modified-Since是否有变,如果没有那就皆大欢喜哈,直接返回304.如果不幸有,不怕,招后还有招.
c)服务器此时再用Etag来判断文件内容是否有改变,哈哈,发现虽然文件有被改动可是内容居然没变,好险差点被蒙过去了!赶紧返回304回去.如果再不幸发现连内容也变了,那没办法了是真的文件更新了,这个时候就要把最新的页面返回给浏览器了.
注意:
1)http缓存只对Get请求有效,对Post没效果哈
2)Etag如果是在分布式下,需要保证不同服务器上资源的Etag的唯一性,可以像上文所说的用文件内容md5作为Etag哈,或者用其它的方式产生Etag,总之要保证同个文件内容要有一样的Etag.
3)F5或者强制刷新会使Expries失效,这个时候浏览器必会发生一次服务器请求