1 前言
页面缓存一直是前端开发中我们关注比较少的,研究了一些资料,总结了一些心得,记录下来共同探讨。
合理的页面缓存可以让页面执行的效率提高很多(在第一次访问或者CTRL+F5强制刷新的时候,缓存的效果是体现不出来的),而不是我们一味的设置cache-control为no-cache。
当然了如果缓存使用不当,也会带来麻烦,比如缓存参数设置不合理,会导致请求得到的是旧的页面元素。
2 缓存原理
首先一开始我们要明确页面缓存的原理以及过程。
缓存的原理大体是在浏览器对资源的第一次请求之后,把资源中的一部分存储在计算机的临时文件空间,再次请求的时候,按照特定的策略加载缓存的资源,减少HTTP请求次数与传输数据量,以此提高浏览效率。
以下是一个请求的过程讲解。
2.1 第一次请求
打开一个浏览器如IE,这时候浏览器会对自身设置的参数进行加载,其中就包括缓存设置参数。
接下来我们在地址栏输入一个url,这时候浏览器会发送一个简单的HTTP请求报文头给应用服务器,这个报文头主要包含的信息是请求的url,接受的编码约定,缓存控制等信息。
典型的请求报文头:
服务器接受到了请求报文头,一堆业务处理完毕之后,会给出HTTP响应报文,响应报文格式分为报文头和报文体,响应报文头中的信息是很重要的,我们以一个图片响应报文头为例讲解相关内容:
这个响应报文头可以看到以下信息:
响应状态码是200,说明是正确返回。
cache-control设定了有效时间,在这个时间内新打开新网页(或者地址栏回车)不需要去请求服务器。
报文内容类型是image/gif。
最近修改时间是2008-7-30 10:23:00,最近修改时间在浏览器刷新的时候有很大的用处,浏览器刷新的时候,会发送对该图片请求的报文,得到的响应报文中如果最近修改时间和缓存的一致,那么浏览器将会从缓存中读取该图片的信息(状态码是304),如果两个时间不一致,会从服务器请求得到最新的文件,并缓存。
服务器类型等其他信息。
该响应报文接受到之后,浏览器解读报文体内容,并打开显示给用户,这是主要的工作。
除此之外,浏览器还根据报文头的信息,确定一些缓存规则,比如no-cache的不缓存,设置了max-age的再次打开不请求等,更多的信息可以参考三、四章节。
2.2 再次请求
再次请求的时候,才是缓存显现身手的时候。
还是以上面请求的那个图片(设置了max-age)为例。
如果这个时候我们在地址栏按照原有url回车的话,针对该图片,是没有发送HTTP请求的,更没有请求服务器资源,浏览器直接从缓存空间读取该图片。
如果这个时候刷新,则是发送HTTP请求,得到以下的响应报文:
检查服务器,得知该文件没有修改,那么浏览器将从缓存中获取该图片。
3 缓存对象
页面缓存,主要缓存什么东西呢?我们首先要明确一下Content-Type的概念。
我们知道HTTP协议是类似MIME的消息结构,MIME类型是和文档的后缀名相关的,我们在请求服务器然后获取到数据,我们只得到了数据,并不知道文档后缀的名字(比如没办法区分css和js),这时候服务器必须使用附加的信息来告诉客户端数据的类型,服务器在发送真正的数据之前,就要先发送标志数据的MIME类型的信息,这个信息使用Content-type关键字进行定义,常见的有text/html、text/css、application/x-javascript、image/gif、image/jpeg、audio/x-mpegurl等,如果这些类型是浏览器能直接识别的,那么浏览器就直接打开显示出来,否则要关联注册表,找到对应的程序来打开,比如audio。
更多的内容可以百度一下MIME类型。
页面缓存缓存对象除了text/html之外,image/gif、image/jpeg的cache-control一般都通过设置max-age来实现缓存,application/x-javascript通过Last-Modified或者ETags来实现。
4 缓存规则
怎么来设定缓存呢?主要有以下三种手段:
4.1 默认缓存规则
应用服务器是有默认缓存规则的,比如缓存对象他content-type=text/html,应用服务器给出的默认响应报文头中,cache-control一般都设置为private。
常见的tomcat和weblogic默认缓存规则是存在差异的。当然这些应用服务器的默认缓存规则是可以通过配置来修改的。
4.2 单个设定
单个设定就是我们常见的,在html的meta区域设置cache-control,max-age,expires等。应用服务器在解析到这些参数之后,会在响应报文中明确指出,告诉浏览器当前页面的缓存规则。
具体内容可以参考《http meta 简介》。
4.3 批量设定
l 过滤器
对同一类页面元素实施相同的缓存策略,可以使用过滤器来实现,通过判定缓存对象类型,在相应中添加相同的缓存规则。
具体代码参考web.xml和ResponseHeaderFilter.java。
l eTags
参考http://www.infoq.com/articles/etags。
5 IE重新浏览方式对缓存的影响
(这部分内容是自己测试的成果,相信存在误差。)
IE不同的重新浏览方式对应的数据请求是有差异的(都可以使用HttpWatch明确看到相应的报文内容)。
5.1 IE前进,后退
一般来说这种重新浏览方式数据都是取自缓存。
比如Cache-control设定为private、must-revalidate、max-age的内容。
Cache-control为no-cache,还需要再次请求服务器,因为这种情况是不会在浏览器缓存区留下任何痕迹。
5.2 IE转到/地址栏回车
这种情况是根据IE的设置来确定怎么访问数据,IE的Internet选项中Internet临时文件的设置有这么几个选项:每次访问网页时检查、每次启动IE时检查、自动(默认)和不检查,这几个选项的设定其实是影响发送的HTTP报文表头的。
仅仅看一下默认情况(自动),自动的话,IE查看指定网页的时候不检查上次已经查看过的这个网页是否已经发生改变(有点绕)。
比如text/html(private)依旧会去请求服务器数据,application/x-javascript等就不再请求服务器了,而是来自缓存。指定了max-age值的img也一样,不会再去请求服务器,直接取自缓存。
详细解读可以参考IE的帮助信息。
5.3 IE新窗口,如链接打开
如果页面指定cache-control的值为private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。
如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器。
5.4 IE刷新
不管cache-control的为何值,都会检查服务器。
检查要访问网页的最新版本,如果存在最新版本,则返回最新网页的内容,并更新缓存;如果不存在最新版本,则只返回标题,内容去缓存中获取。
5.5 IE强制刷新(CTRL+F5)
获取要访问网页的服务器最新版本,返回最新的版本,并删除缓存中的相应内容,将最新的内容写入缓存。
其实强制刷新情况下,请求的HTTP报文头里,Cache-control为no-cache。
5.6 脱机工作
这是一种比较特殊的重新浏览方式,这种情况下是没有任何面向服务器的请求过程的,直接去浏览器的缓存寻找数据,如果缓存没有命中,脱机就没办法工作了。
显而易见的是,no-cache方式,是没办法脱机工作的。