1) 缓存减少了冗余的数据传输,节省了网络费用。
2) 缓存缓解了网络瓶颈的问题,不需要更多的网络带宽就能更快的加载页面。
3) 缓存降低了对原始服务器的要求,服务器可以更快的响应。
2.缓存分类
1)私有缓存
常见就是我们的浏览器里内置的缓存。
2)公有缓存
常见的就是代理缓存,不多介绍。
3.缓存的处理流程
处理流程图,如上所示,下面分步骤具体介绍:
1)请求处理
用户发起一个http请求,缓存获取到URL,根据URL查找是否有匹配的副本,这个副本可能在内存中,也可能在本地磁盘。
2) 新鲜度检测
如果缓存中存在所请求资源的副本,则进行新鲜度检测。新鲜度检测举个简单的例子,我们在商店买了一瓶汽水,汽水瓶上肯定会标有过期时间,我们会根据这个过期时间和现在的时间做对比,看看饮料过期了没,如果没过期,我们正常喝就行了,如果已经过期,我们肯定要找商家。。。其实这就是一个新鲜度检测的过程,HTTP请求的新鲜度检测流程也是这样的,HTTP发起一个请求时,发现缓存中有相应的副本,接着就会检查这个副本有没有过期,如果没有过期,直接使用。如果已经过期,则进行再验证。具体的实现在下面会介绍。
3)服务器再验证
缓存中的文档过期了并不代表他和服务器上的不一样,所以这个时候就需要问问服务器,过期的这段时间里这个文档到底有没有改变。如果改变了,缓存就会获取一份新的文档副本,然后发送给客户端。如果没有改变,缓存只需要获取新的首部,包括一个新的过期时间,并对缓存中的首部更新。
4)创建响应并返回
我们希望缓存看起来就像是来自原始服务器一样,缓存将已缓存的服务器响应首部作为响应首部,发送给客户端。
4.保质期的实现
HTTP中,通过Cache-Control首部和Expires首部为文档指定了过期时间,通过对过期时间的判断,缓存就可以知道文档是不是在保质期内。Expires首部和Cache-Control:max-age首部都是来告诉缓存文档有没有过期,为什么需要两个响应首部来做这件简单的事情了?其实这一切都是历史原因,Expires首部是HTTP 1.0中提出来的,因为他使用的是绝对日期,如果服务端和客户端时钟不同步的话(实际上这种情况非常常见),缓存可能就会认为文档已经过了保质期。
HTTP 1.1为了修正这个问题,引入了Cache-Control:max-age首部,这个首部使用相对时间来控制保质期,让一切变得更加合理。举个例子,我们买了一瓶汽水,如果使用Expires首部来标注保质期,就会这么写:饮料过期时间:2012年12月21日,如果某个2货不知道今天多少号,他还真不知道这饮料过期没,我小时候饮料都这么写。后来,有个挺有名的卖牛奶的,大概就叫蒙牛,他发明了一种标注保质期的方法,他怎么搞了?他这么写:保质期:12个月,行,牛逼了,我牛奶一年前就生产出来的牛奶,今天要发给厂家,发之前,先往包装上印上生产日期(当然是印发货那天),然后告诉你,明年才过期,这多聪明,搞成相对的,毒死你。也许HTTP 1.1借鉴了这个伟大的发明,于是就有了Cache-Control:max-age首部。
5.服务器再验证的实现
缓存要问问服务器,牛奶已经过期了,到底还能不能喝。我说错了,是文档,不是牛奶。HTTP中,使用两个请求请首部来完成这个功能:If-Modified-Sice和If-None-Match。为啥又要两个首部来完成这个功能了?答案还是因为历史的原因。一开始使用 If-Modified-Sice:<date>首部,date是上一次缓存牛奶时,响应中Last-Modified首部的值。
客户端拿着这个值,问服务器,这段时间内这个牛奶你有没有修改过?服务器看了看这个牛奶的修改时间,如果没有修改过,会返回一个304 Not Modified的响应;如果修改过,把最新的牛奶返回给客户端。后来,人们发现这样有问题,因为就算修改时间变化了,文档也不一定发生改变!于是乎,就有了 If-None-Match:<tag>首部,tag是上一次缓存文档时,响应中Etag的值,Etag是一种唯一标识资源的方式,就像java中的hashcode,如果hashcode不一样,那么两个对象肯定不一样!
6.试探性过期
如果响应中既没有Cache-Control:max-age首部又没有Expires首部,缓存可以计算出一个试探性最大使用期。这东西打个比方就是缓存会根据响应的Last-Modified来决定这文档靠不靠谱,需不需要再验证,如果Last-Modified中的日期是很早之前,那缓存就认为这文档挺靠谱,近期之内应该不会变化;如果Last-Modified中的日期是最近几天,那缓存可能就认为这文档可能经常改变,不靠谱。当然这么粗略的判断想想就知道不严谨,所以我们一定要设置Expires首部和Cache-Control首部。
7.写在最后
如果你是个好学者,看完这个文章,你可能会迫不及待的打开你的chrome浏览器,F12,观察oschina的HTTP信息。这个时候的你,肯定和几个月前的我一样茫然,因为你发现我上面讲的很多东西再这里被现实无情推翻了。看看这个讨论记录,这是几个月前我在OSC上问的。之所以会出现这个情况,是因为chrome为了保证牛奶的安全放心,所以他不太信任包装上的保质期标识,每次都问问服务器(再验证),牛奶有没有变化,没变化的话他就直接喝了!一切都是为了安全!