`
zl198751
  • 浏览: 272957 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

浏览器缓存

阅读更多

作为一个后端开发工程师,提起缓存,我们首先想到的是linux memory buffers、memcached、buffer pool等等,从操作系统、到缓存服务器、再到数据库缓存,等等。但是我们往往忽略了另一项缓存措施,那就是浏览器缓存。用户请求服务器上内容如果可以缓存到用户的浏览器当中,至少对于这个用户而言,如果请求同样的内容,便可能不需要再次从服务器获取,直接从浏览器缓存中获取即可。这样既可以减少服务器的计算开销,也可以避免有些内容由于不必要的重复传输而带来的带宽浪费。作为整体缓存的方案以及性能优化的当中的一部分,浏览器缓存应该被重视起来。

缓存内容:

浏览器一般会在用户的文件系统中创建一个目录,用于存放缓存文件,并给每个文件标识一些必要的标记,比如过期时间等。当然不同浏览器具体做法会有所不同。

以win7下环境下为例:

ie会将缓存文件存放在类似于这样的一个目录下:C:\Users\cesc.wangl\AppData\Local\Microsoft\Windows\Temporary Internet Files

而firefox则存在:C:\Users\cesc.wangl\AppData\Local\Mozilla\Firefox\Profiles\htiosoai.default\Cache

当然你会发现他们的缓存方式有所不同,这是出于浏览器内部的设计,再此不做过多讨论。

浏览器不仅使用硬盘来存储浏览器缓存,还会使用内存,它们会将命中率较高的缓存内容同时存储在内存当中,以便浏览器读取缓存时更加高效和快速。

针对firefox的浏览器缓存,我们可以使用about:cache命令来查看其具体内容:

alt
我们看到具体缓存内容以及相关的标记。

缓存协议:

虽然是浏览器缓存,但是缓存的内容还是来自服务器,因此缓存的使用规则(如:过期时间)还是要依赖于服务器的判断给出。而浏览器和服务器之间通过Http协议进行沟通,因此浏览器缓存的使用规则也就是通过Http协议进行沟通的。因此,有效的使用浏览器缓存,必须对Http协议缓存部分有一定理解,下面我们会针对这部分进行说明:

缓存协议添加的位置:

Http头信息,通过在Http头信息当中添加相应的缓存标识,达到浏览器与服务器缓存协商的目的,而且这种方式可以覆盖到所有Http请求;

缓存协议适用的请求类型:

浏览器缓存都是基于Get类型的请求的情况,而Post类型的请求,浏览器一般不会采取缓存。

基于最后更新时间的缓存协议:

Last-Modified,这是服务器端获取的针对此内容的最后修改时间,会作为响应头带给浏览器,浏览器下次请求此url的时候,会在请求头当中添加If-Modified-Since,把浏览器上次保存的最后修改时间发送给服务器,服务器此时使用这个时间与服务器实际内容的最后修改时间做比较,如果未过期,服务器输出304 Not Modified状态码,告诉浏览器服务器对应内容未更新,可以使用浏览器本地缓存;如果已过期,服务器直接将最新的内容和最新的修改时间传回给浏览器,浏览器直接展示最新的内容。

alt

如何获取最后修改时间呢?针对静态内容,web服务器(如Apache)会获取操作系统上物理文件系统中对应文件的最后修改时间,填充在这里,作为响应头信息,直接返回给浏览器。而动态内容,处理麻烦一些,需要编码进行以上逻辑的判断,并将对应信息放置到头信息当中,并处理好对应的状态码。

关于提升的效果,也要分开来看:

静态资源:提升效果很明显,节省了Http响应正文的传输开销和web服务器读取静态文件的IO消耗。

动态资源:也会节省Http响应正文的传输开销,但是由于是动态资源,因此判断过程还是会流转到后端的Java容器,而针对不同的判断规则,对于后端服务器资源的节省效果各有不同。

还要提一下这种形式的另外一种实现,就是ETag,这是Http 1.1支持的另一种缓存协议。但是它和Last-Modified很相像,原先判断时间的方式,转而判断ETag编码,而ETag编码规则则由服务器端来控制,各个服务器的实现有所不同,总之,只要能够起到标识内容的作用即可。ETag的优势是在于可以应对文件频繁更新,而文件的内容可能并没有变化的场景。

altalt

基于缓存截止时间的缓存协议:

之前提到的基于最后更新时间的缓存协议,由于需要进行一个对时的过程,因此无法避免的会对服务器增加一次请求,有没有不需要请求服务器的方式,进行浏览器缓存呢?当然有,Http协议提供Expires,作为基于缓存截止时间的缓存协议。这个时间是由服务器端作为响应头,传输给浏览器,浏览器获取到此时间,之后的针对此内容的,早于此过期时间的请求,全部会走浏览器缓存,从而也再不需要发送请求与服务器对时,这样完全节省了带宽和服务器处理等开销。

如何获取缓存截止时间呢?针对静态内容,web服务器默认情况下是不开启此功能的,如果需要,可以进行配置,如Apache当中可以添加mod_expires模块,进行相关的配置。其实对于常见的静态文件格式,即便是web服务器返回的Http响应头中没有Expires标记,浏览器也会根据一些自身实现的逻辑,预期一个过期时间。

动态内容还是需要后端服务器进行编码,设置缓存截止时间。

另外,有一个问题,由于是基于缓存截止时间的缓存协议,因此时间的比对需要浏览器自身来完成,而缓存截止时间则是服务器给出的,这样就会产生一个问题,如果用户本地时间和服务器时间不一致的话,那就会影响到浏览器缓存的使用。因此,Http 1.1当中使用Cache-Control来解决此类问题。Cache-Control当中的max-age指定了缓存过期的相对时间,单位是秒,由于是相对时间,因此也就不会出现浏览器和服务器时间不一致的问题了。

web服务器用于兼容Http 1.1,在开启Expires都会默认自动添加Cache-Control。浏览器端,主流浏览器都将Http 1.1视为首选,因此对时的逻辑判断也会优先考虑Cache-Control的配置。

alt

浏览器请求方式:

浏览器的请求方式的不同,会导致不同的请求头,亦会导致不同的缓存使用策略,下面简单介绍一下:

单击浏览器地址栏的“转到”按钮或者通过超级链接跳转到页面:

这种方式允许浏览器以最少的请求来获取网页的数据,浏览器会对所有的没有过期的内容直接使用浏览器缓存,以上介绍的两种缓存协议都是生效的。

F5或者单击浏览器的刷新按钮:

这种方式是一般的刷新方式,此方式允许浏览器在请求头中附加缓存协议,但是不允许直接使用浏览器缓存,即此方式只针对“基于最后更新时间的缓存协议”(即Last-Modified)有效,而针对“基于缓存截止时间的缓存协议”(即Expires)无效

Ctrl+F5:

此种方式称为强制刷新,此方式下,会使得网页以及其中的所有组件(图片、JS等)都直接向服务器发送请求,并且不使用任何缓存协议,最终的目的即获取所有内容的最新版本。在实际使用中,很少有用户会这样操作。alt

 

正如上图展示的一样,Ctrl+F5会导致浏览器在请求头当中忽略所有缓存信息,而且会带上Cache-Control:no-cache以及Pragma:no-cache的信息,告诉服务器,此请求不需要任何缓存。

题外话:上文提到的缓存协议不仅仅使用在浏览器缓存上,web服务器缓存以及反向代理缓存都会使用相同的缓存协议,之后文章中会再次提起以上内容。

当前网站如何使用浏览器缓存?

针对静态内容,web服务自身会使用基于最后更新时间的缓存协议,节省响应正文的传输以及服务器端的消耗,其中使用最广的是在图片CDN以及JS、CSS的独角兽上。

针对动态内容,在网站非核心的信息,自身数据由延时的信息,可以考虑使用浏览器缓存,降低浏览器对服务器的多余的请求消耗,节省服务器的资源。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics