论坛首页 编程语言技术论坛

Rails每周一题(四): Browser Cache

浏览 2636 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-04-06   最后修改:2009-08-08

注意,这里讲的是浏览器端的cache。关于Rails服务器端的cache,以后专门开题再讲。

 

HTTP协议对Cache 的支持

 

总而言之,cache机制是为了减少发送request的次数(过期模型),还有就是减少发送整个response的机会以减少网络带宽的使用(验证模型)。

 

在HTTP协议里面,主要有三种控制cache的方式。

 

1. Cache-Control

 

Cache-Control有一系列的指令来告诉应该对cache采取怎样的处理,比如no-cache, no-store, max-age, must- revalidate等。Cache-Control也是唯一的显式指令。其它模式,比如过期模型和验证模型,都是隐式地告诉应该怎样处理cache。

 

Cache-Control有很多不同的指令。如果有明显的冲突,一般采用最严格的解释方式。

 

2. 过期模型(Expiration Model)

 

应用了过期模型,在设定的过期时限之前,不会向服务器发起真正的request,而是直接返回cache。

 

这种方式一般用在一些静态页面很多,或者基本上在一段时间内不会改变的页面上。比如google的主页一般在几个礼拜内都不会变化。

 

服务端通过Expires头或者Cache-Control的max-age指令来设定过期时间(后者的优先级更高,如果同时指定,后者覆盖前者)。

 

3. 验证模型(Validation Model)

 

当cache有一个旧的entry,想用它作为一个客户端请求的response时,它需要检查cache的entry是否仍可用(这里不是基于应用了过期模型的cache方式,而是默认cache方式)。这就是验证模型。

 

服务器端会进行验证,如果验证确实match,则返回304(Not Modified)状态码,但不会返回entity-body。否则则返回整个response(包括entity-body)。

 

验证模型可以使用时间、checksum等来进行验证。跟验证模型相关的指令有:last-modifed, if-modified-since, ETag, if-none-match等。


对于这三种模式在冲突时的优先级关系,我没有很好地去分析。但通过某些行为可以看出,Expire优先于Validation,而某些Cache-Control指令又能把Expires或者Validation干掉。

 

现代web服务器和浏览器对Cache的支持

 

用firebug跟踪了一下,发现现在的web服务器(即使是Mongrel)和浏览器对cache的工作做得相当好。对于如css,javascript,image等文件,都会自动采取验证模型来进行cache。

 

比如第一次对一个静态文件进行访问时,response header包含这样一个值:

 

Last-Modified	Wed, 25 Mar 2009 15:07:30 GMT
Etag"49ca48b2-1faca-140dbf"

 

后续的请求头里面会有如下一些值:

 

If-Modified-Since	Wed, 25 Mar 2009 15:07:30 GMT
If-None-Match	"49ca48b2-1faca-140dbf"
Cache-Control	max-age=0

 

相应的response status code是304(Not Modified),且response header变成:

 

Connection	close
Date	Mon, 06 Apr 2009 09:32:46 GMT
Etag	"49ca48b2-1faca-140dbf"

 

 

Rails对动态页面cache的支持

 

http://guides.rubyonrails.org/caching_with_rails.html 的Conditional GET support部分。

 

 

Rails鼓励我们采取怎样的cache方式

 

Rails会默认为javascript,css,image等资源文件的path后面附加上文件的最后修改时间。为啥要这么做?很明显,Rails是在鼓励你使用过期模型去cache这些资源文件。

 

比如在Apache里,使用这样的配置来使这些静态资源文件被cache。

     ExpiresActive On
     <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
          ExpiresDefault "access plus 1 year"
     </FilesMatch>
 

添加了这个配置之后。对js等文件请求的reponse头里面就会多了如下两个header。

 

Cache-Control	max-age=31536000
Expires	Tue, 06 Apr 2010 09:28:49 GMT
 

在随后的请求中,只要文件还没过期,客户端就不需要再去发起request获取被Cache的资源。同时,一旦文件有任何改变,浏览器都能获取到新的文件。因为path已经根据最后修改时间改变。

 

唯一值得注意的是,因为浏览器限制对同一个地址一般最多同时发起两个请求,所以我们会使用了多台资源服务器(查看AssetTagHelper Doc 了解怎样使用多台资源服务器),那么保证每台服务器时间的同步是至关重要的。不然会因为资源服务器的随机选择,url后附着的时间戳经常改变,致使cache失效。

 

Cache的两条简单规则

 

对于现在的网站应用来说,我很同意以下的两条cache原则。

 

Don't cache HTML

 

1. Use Cache-Control: no-cache for dynamic HTML pages

2. Use the Last-Modified header with the current file time for static HTML

 

Cache everything else forever

 

1. For all other file types set an Expires header to the maximum future date your web server will allow

2. Modify URLs by appending a query string in your HTML to any page element you wish to ‘expire’ immediately.

 

结束!

论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics