什么是ESI
ESI的全称是Edge Side Includes,是一个基于XML的标记语言,目的是在HTTP中组装各种资源。是由Oracle和Akamai等公司提议的,在W3C的网站也可以找到相关规格说明,最新的是2001年的了,也不是什么新东西。传统的cache技能基本都已页面为单位进行缓存,问题就是页面部分的动态内容可能比较多,而且是每个客户端的内容都不一样(比如个人的登录信息,欢迎xxx等。),缓存比较困难。ESI为了能把页面的一部分进行缓存,使用基于XML的标记语言,来描述对page内个内容的缓存情况。这样,服务器(缓存部分)就可以只缓存共同部分了。
ESI有点类似SSI,但是它比SSI功能更丰富。
目前支持/实现ESI的开源服务器包括Squid,Mongrel-ESI等,商用的有Oracle和Akamai的服务器。
要在Rails里支持ESI需要安装两个插件,一个是Mongrel用的插件Mongrel-ESI,一个是Rails用来处理ESI标记(tag)的fragmentFu。两个软件都可以在http://mongrel-esi.googlecode.com找到。
如何安装一下Mongrel-ESI我就不说了,因为我也没有装过,下面的代码我都没有试验过。
下面来看一下ESI的代码,下面是一个测试的例子(转自http://blog.tkmr.org/tatsuya/show/368-rails-10-esi,日文)
- cd /home/my/rails/app/path
- ----index.html-----
- <h1>Welcome ESI!!</h1>
- <p><esi:include src="/welcome/now" max-age="45"/></p>
esi标记里的就是ESI的内容了,应该比较好理解,max-age的意思就是页面缓存保留的时间,这里的话每45秒缓存就会被更新一次。
再来看看控制器里的代码:
- ./script/generate controller welcome now
- ----welcome_controller.rb----
- def now
- render :text => "#{Time.now}"
- end
启动Mongrel_esi:
- mongrel_esi start
- ** Starting Mongrel listening at 0.0.0.0:2000
然后就可以去浏览器里看看了,是不是45秒那个显示的时间才更新一次。
上面的例子是标准的ESI写法,当然Rails中这样写就有点累了,这个时候就需要fragmentFu这个Rails的plugin了。
在ERB里,写法是这样的:
- ./script/plugin install http://mongrel-esi.googlecode.com/svn/trunk/plugin/fragment_fu
- ----/app/view/welcome/index.html.erb----
- <h1>Welcome ESI!!</h1>
- <p><%= render :esi => {:action => "now"}, :ttl => 45.seconds %> </p>
ttl这个名字比较亲切。
当然,ESI里面也能使用Cookie或者Http的request数据:
- #query string
- <p><%= render :esi => "/users/name/$(QUERY_STRING{my_name})" %> </p>
- #Cookie
- <p><%= render :esi => "/users/home/$(HTTP_COOKIE{UserID})" %> </p>
除此之外,ESI还有异常处理机能。因为ESI指令的include可以指向别的地址,所以,取得cache内容也可能失败。
比如下面的代码(来自http://revolutiononrails.blogspot.com/2007/08/advanced-rails-caching-on-edge.html
)
- <esi:try>
- <esi:attempt>
- <esi:include src="/latest" max-age="5" timeout="1"/>
- </esi:attempt>
- <esi:except>
- <esi:include src="http://static.foo.com/latest" max-age="5" timeout="1"/>
- </esi:except>
- </esi:try>
这个也应该比较好理解,如果尝试1秒内取得不到/latest的话,cache服务器就会放弃,而去取静态页面的内容。
另一不错的功能就是Invalidation,就是使已有的cache的内容失效,因为它cache的内容已经被更新过了。在Rails自带的cache功能里需要在action调用失效方法的,或者用sweeper回调。ESI则有invalidate指令:
- <esi:invalidate>
- <?xml version="1.0"?>
- <!DOCTYPE INVALIDATION SYSTEM "internal:///WCSinvalidation.dtd">
- <INVALIDATION VERSION="WCS-1.1">
- <OBJECT>
- <BASICSELECTOR URI="/foo/bar/baz"/>
- <ACTION REMOVALTTL="0"/>
- </OBJECT>
- </INVALIDATION>
- </esi:invalidate>
参考链接:
http://revolutiononrails.blogspot.com/2007/08/fragmentfu-fun-with-fragments.html
http://revolutiononrails.blogspot.com/2007/08/advanced-rails-caching-on-edge.html
http://www.w3.org/TR/esi-lang
http://blog.tkmr.org/tatsuya/show/368-rails-10-esi