富web应用程序的本质意味着它们的动态。不管你的应用程序多么有效率,每一个请求比起静态文件来讲总会存在不少的耗费。对于大多数web程序来 说,这没什么。 Symfony2很是的轻快,不管你作些严重超载的请求,每一个请求将会获得很快的回复,而不会对你的服务器形成压力。可是随着你站点的成长,负载将成为一 个严重的问题。对每一个请求处理应该只被正常执行一次。这就是缓存真正要达成的目标。php
站在巨人肩膀上的缓存:
提升一个应用程序执行效率的最有效方法是缓存一个页面的全部输出然 后让后续的请求绕开整个应用程序。固然,这对于高动态性的站点来讲并非老是可能的。Symfony2 缓存系统是比较特别的,由于它依赖于在HTTP规范中定义的简单强大的HTTP cache。没有从新发明新的缓存方法,Symfony2 拥抱在web上定义基础交流的标准。一旦你理解了基础的HTTP校验和过时缓存模式,你就会彻底掌握了Symfony2的缓存系统。html
第一步:一个网关缓存(gateway cache),或者反向代理。是一个坐在你应用程序前面的对立的层。反向代理缓存来自于你应用程序的响应并使用这些缓存响应在某些请求到达你应用程序以前 来回复它们。 Symfony2提供了本身的反向代理,也可使用其它任何的反向代理。前端
第二步:HTTP缓存 (HTTP cache)头用于和网关缓存以及任何其位于客户和你的应用程序之间的其它缓存交流。Symfony2 提供了和缓存头交互的预设行为和强大接口。web
第三步:HTTP 超时和校验时用于决定一个缓存内容是否新鲜和陈旧的两种模式。算法
第四步:ESI(Edge Side Includes)容许HTTP缓存被用于独立缓存页面片断(甚至是嵌套片断)。使用ESI,你甚至能够缓存一个完整的页面60分钟。但一个嵌入式边栏缓存只有5分钟。数据库
使用网关缓存
当使用HTTP缓存时,缓存是跟你的应用程序彻底分离的,它位于你的请求客户端和应用 程序之间。该缓存的工做就是从客户端接收请求并把它们传递回你的应用程序。同时它也将接收从你的应用程序返回的响应并把它转给客户端。能够说它是你的应用 程序和请求客户端之间请求-响应交互的中间人。bootstrap
按照这个思路,缓存会保存被认为是“可缓存的”每个响应回复。当一样的请求再次传来时,该缓存会把本身缓存的响应直接回复给请求客户端,而完 全忽略你的应用程序。这种类型的缓存就是HTTP网关缓存。目前有不少这类缓存,好比Varnish,Squid in reverse proxy mode和Symfony2 反向代理等。数组
缓存类型
一个网关缓存不是缓存的惟一类型。事实上,有三种不一样类型的缓存会截获并使用你的应用程序发出的HTTP缓存头。它们是:
浏览器缓存(Browser caches):浏览器拥有本身的本地缓存,这对你单击"前一步"或者查看图片和其它网络资产时起到了主要做用。
代理缓存(Proxy caches):一个代理缓存是一个多人位于一人以后的共享的缓存。它们大可能是一些大公司或者ISP安装用来减小延迟和网络阻塞的。
网关缓存(Gateway caches):像一个代理,也是一个共享缓存可是是位于服务器端的。通常是网络管理员安装它们,它使得网站更具可伸缩性,可靠性和高效性。网关缓存有时候被称为反向代理缓存,代理缓存,更或者是HTTP加速器。浏览器
Symfony2 反向代理
Symfony2拥有一个用PHP编写的反向代理(也叫作网关 缓存)。开启它后,来自你应用程序的可缓存的响应回复将会开始被马上缓存。安装它相也当容易。每个新的Symfony2应用程序都有一个预配置缓存内核 (AppCache)包含了一个默认的AppKernel。该缓存内核就是个反向代理。要开启缓存,修改前端控制器代码使用缓存内核:缓存
// web/app.php require_once __DIR__.'/../app/bootstrap.php.cache'; require_once __DIR__.'/../app/AppKernel.php'; require_once __DIR__.'/../app/AppCache.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('prod', false); $kernel->loadClassCache(); //使用AppCache包裹默认的AppKernel $kernel = new AppCache($kernel); $kernel->handle(Request::createFromGlobale())->send();
缓存内核会马上扮演一个反向代理的角色,缓存来自你应用程序的回复把它们发回给请求客户端。
注意,该缓存内核有一个特别的getLog()方法返回一个可以表示在缓存层发生了什么的字符串。
能够在开发环境中来调试和校验你的缓存策略。
error_log($kernel->getLog());
AppCache 对象是一个合理的默认配置,固然你也能够经过重写getOptions()方法来设置可选项对它进行调优。
// app/AppCache.php use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; class AppCache extends HttpCache { protected function getOptions() { return array( 'debug' => false, 'default_ttl' => 0, 'private_headers' => array('Authorization', 'Cookie'), 'allow_reload' => false, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, ); } }
注意,这里不管怎么重写getOptions()方法,其中debug选项将被包裹的AppKernel的debug值自动设置。
下面是一些重要的可选项:
default_ttl: 当没有显式的刷新信息在回复中提供时,一个缓冲实体应该被认为是新鲜的时间秒数。显式的设置Cache-Control 或者 Expires 头会覆盖这个参数值。默认值为0。
private_headers:请求头组,它在回复上触发"private" Cache-Control 行为,不管回复是经过Cache-Control 指令显式的声明是public仍是private 。默认为Authorization和Cookie。
allow_reload: 指定是否容许客户端经过在请求中指定Cache-Control的"no-cache"指令来强迫缓存从新加载。设置它为true时符合RFC2616规范。默认值为false。
allow_revalidate:指定是否容许客户端经过在请求中指定Cache-Control的"max-age=0"指令来强迫缓存从新校验。设置它为true时符合RFC2616规范。默认值为false。
stale_while_revalidate:用于指定一个默认秒数(间隔是秒由于回复TTL精度是1秒),在期间缓存还在后台进行从新校验时能够 马上返回一个陈旧的回复(默认是2);该设置会被stale-while-revalidate HTTP Cache-Control扩展重写(RFC 5861)。
stale_if_error: 指定一个默认秒数(间隔是秒)在这期间缓存能够提供一个陈旧的回复当遇到一个错误时。默认值为60。该设置会被stale-if-error HTTP Cache-Contorl 扩展重写(RFC5861)
若是debug设置为true,Symfony2 会自动添加一个X-Symfony-Cache 头到回复保存着关于缓存点击和丢失的信息。
从一个反向代理到另外一个的转换:
Symfony2反向代理是一个在开发你的站点或者部署你 的站点到一个共享主机而你没法安装任何除PHP代码之外的东西时的很是有用的工具。可是由于使用PHP编写,它不能跟用C写成的反向代理那样快速。这就是 为何咱们推荐使用Varnish或者Squid到你的运营服务器上的缘由。好消息是从一个代理服务器到另一个替换很容易,简单的不用你修改任何程序代 码。你能够开始时使用Symfony2的反向代理等到了阻塞增长时升级到Varnish。
注意:Symfony2 反向代理执行效率独立于应用程序的复杂性。由于应用程序核心仅仅在请求须要被转发到它时才被启动。
HTTP缓存说明:
为了发挥可用缓存层的优点,你的应用程序必须能传达它的哪一个回复能够被缓存,何时/怎样 缓存会变成陈旧的规则。这些是经过在回复(response)上设置HTTP 缓存头来实现的。
记住,"HTTP"只不过是一种web客户端和服务器之间交流的简单文本语言。当咱们说HTTP 缓存时,咱们说的是它容许客户端和服务器交换信息相关的缓存。
HTTP指定了4个Response缓存头,咱们须要关注一下:
Cache-Control
Expires
ETag
Last-Modified
其中最重要的也是万能的头是Cache-Control头,它实际上是一个各类缓存信息的集合。
Cache-Control Header
Cache-Control头是惟一的一个其内部包含了各类各样的关于一个response是否能够被缓存的信息。每条信息之间用逗号隔开。
Cache-Control:private,max-age=0,must-revalidate Cache-Control:max-age=3600,must-revalidate
Symfony 提供一个Cache-Control头的抽象,使它的建立更加可控。
$response = new Response(); // 标记response为public仍是private $response->setPublic(); $response->setPrivate(); // 设置private或者shared 的最大年龄 age $response->setMaxAge(600); $response->setSharedMaxAge(600); // 设置一个自定义的Cache-Control 指令 $response->headers->addCacheControlDirective('must-revalidate', true);
公共vs私有 Response
网关缓存和代理缓存都被认为是“共享”缓存,由于它们缓存的内容是 被多用户共享的。若是一个特定用户的回复曾被错误的存储到共享缓存中,它之后可能被返回给无数的不用用户。想象一下,若是你的帐户信息被缓存而后返回给每 一个后来请求他们本身帐户页面的用户。要处理这种状况,每一个回复可能都要设置时public仍是private。
public 说明给回复可能被private和共享的缓存保存。
private 说明全部的或者部分的回复信息时给一个单独用户的,因此不能缓存到共享缓存中。
Symfony 谨慎地默认每一个回复为private。 要使用共享缓存的优势(好比Symfony2反向代理),回复必须被显式的设置为public。
安全方法:
HTTP缓存仅仅为安全方法工做(好比GET和HEAD)。要安全意味着当它为某个请求服务时历来不会改变服务器上应用程序的状态。(固然你能够写日志信息,缓存数据等)。这里有两个很合理的后果(consequences):
当你的应用程序回复一个GET或者HEAD请求时,你绝对不会改变你应用程序的状态。即便你不用网关缓存,代理缓存的存在乎味着任何GET和HEAD请求可能会或者可能不会真的达到你的服务器。
不要指望PUT,POST或者DELETE方法被缓存。这些方法被使用意味着你应用程序状态的改变。缓存它们将阻止某种请求访问或者改变你的应用程序。
缓存规则和默认设置
HTTP 1.1 默认状况下容许缓存任何事情除非有一个显式的Cache-Control头。实践中,大多数缓存当请求有cookie,一个受权头,使用一个非安全的方法 (好比PUT,POST,DELETE)或者当请求有一个重定向代码时,不会进行任何缓存活动。
当开发者没有作任何设置时,Symfony2 会自动按照下面的规则设置一个合理的比较保守的Cache-Control头:
若是没有缓存头被定义(Cache-Control,Expires,ETag 或者Last-Modified),Cache-Control被设置为no-cache,意味着该response将不会被缓存。
若是Cache-Control 为空(可是有另外一个缓存头存在),它的值被设置为private,must-revalidate;
若是至少一个Cache-Control指令被设置,而且没有'public'或者‘private'指令被显式的添加,Symfony2 会自动添加一个private指令(除去s-maxage 被设置的状况)。
HTTP过时和校验
HTTP规范定义了两个缓存模型:
过时模型,你只须要经过包含一个Cache-Control和/或者一个Expires头来指定一个Response应该多长时间被考虑“新鲜”问题。缓存理解过时将再也不让相同的请求回复,直到缓存的版本达到它过时时间成为“stale"陈旧。
校验模型,当页面时真正的动态页面时(他们的展示常常变化),校验模型就常常须要了。这种模型,缓存存储response,可是要求服务对每一个请求是否缓存response依然进行校验。
应用程序使用惟一的response 标示符(ETag 头) 和/或者 时间戳(Last-Modified 头)来检查页面自从被缓存后是否放生了变化。
这两个模型的目标是经过依靠一个缓存存储并返回"新鲜" response,使得应用程序从不生成相同的response两次。
过时:
过时模型是在这两个模型中是更加有效和简单明确的模型,它应该在任什么时候候都有被使用的可能。当一个response使用一过时方式被缓存,缓存将存储response并为请求直接返回它而不去访问应用程序,直到它过时。
过时模型能够被熟练的使用一两个,几乎相同的,HTTP头:好比 Expires或cache - control。
过时和Expires 头
根据HTTP规范,Expires头字段提供一个日期/时间,过了这个日期或时间后它的response就被认为是陈旧的了。Expires头能够被Response的setExpires()方法设置。它要求一个DateTime实例做为输入参数。
$date = new DateTime(); $date->modify('+600 seconds'); $response->setExpires($date);
生成的HTTP头的结果以下:
Expires: Thu, 01 Mar 2011 16:00:00 GMT
注意,由于规范的须要setExprise()方法会自动把日期转换为GMT时区。
咱们注意到在HTTP规范1.1版以前,源服务 不须要发送一个Date头。 所以缓存(好比浏览器)可能须要依靠它本地的始终来评估Expires头,形成计算生命周期时时钟误差。 Expires头的另外一个限制是规范规定:"HTTP/1.1服务不该该发送Expires日期将来超过一年。"
过时和Cache-Control 头
由于Expires头的限制,大多时候,你应该采用 Cache-Control头来替代它。回想一下,Cache-Control头是用来指定多个不一样缓存指令的。对于过时来讲,有两个指令,max- age 和 s-maxage。第一个被全部的缓存使用,然而第二个仅仅被用于共享缓存。
// 设置一个秒数,过了这个秒数后response就被认为是陈旧的了。 $response->setMaxAge(600); // 同上,可是只用于共享缓存。 $response->setSharedMaxAge(600);
Cache-Control头将使用以下格式(它可能还有其它指令):
Cache-Control: max-age=600, s-maxage=600
校验:
一旦底层数据发生变化须要马上对缓存资源进行更新时,过时模型就显得力不从心了。在过时模型下,应用程序不会被要求返回更新的response直到缓存最后过时变为陈旧内容之后。
校验模型解决了这个问题。在校验模型下,缓存持续保存response。不一样的是,对每个请求request,缓存都询问应用程序缓存的 response是否依然有效。若是缓存仍然有效,你的应用程序应该返回一个304状态码和一个空内容。这告诉缓存它能够为请求用户返回它缓存的 response。
在这个模型下,你主要节省了带宽由于描述不会发送两次到相同的客户端(而是发送一个304回复代替)。可是,若是你仔细设计你的应用程序,你可能能忍受304 response须要的最小数据并节省CPU。
304状态码意味着没有修改。它很重要由于它没有包含整整的被请求内容,而只是一个轻量级的导向集,它告诉缓存它应该使用它如今保存的版本回复请求。跟过时相似,也有两个不一样的HTTP头能够被用来实现校验模型: ETag和Last-Modifed
校验和ETag头
ETag头是一个字符串(也叫"entity-tag")它是目标资源一 个表现的惟一标识。它彻底由你的应用程序来生成和设置。 好比,若是 /about 资源被缓存保存时取决于日期和你应用程序的返回内容。一个ETag像一个手印,被用来快速的比较一个资源的两个不一样版本是否等效。
像手印,同一个资源的全部表示形式中每一个ETag必须是惟一的。让咱们来简单实现一个生成ETag使用md5加密的回复内容做为内容:
public function indexAction() { $response = $this->render('MyBundle:Main:index.html.twig'); $response->setETag(md5($response->getContent())); $response->isNotModified($this->getRequest()); return $response; }
Response::isNotModified()方法把和Request一块儿发送的ETag与Response上的ETag进行比较。若是两个匹配,方法自动设置Response状态码为304。
这个算法很是简单也很是通用,可是你须要在能计算ETag以前建立一个完整的Response,校验模型是次优选择。换句话说,它节省了带宽,单没有节省CPU利用。
Symfony2还经过向setETag()方法传入true做为第二个参数,来支持弱ETag。
校验和Last-Modified 头
Last-Modified头是校验模型的第二种形式。根据HTTP规范,”Last-Modified 头字段指定日期和时间,在这个时间源服务器相信该表现是最后被修改版。“
换句话说,应用程序决定基于自动缓存内容被缓存后是否被更新过来判断缓存的内容是否要被更新过。举个例子,你可使用最新更新日期为全部须要计算资源表现的对象做为Last-Modified头的值:
public function showAction($articleSlug) { //... $articleDate = new \DateTime($article->getUdateAt()); $authorDate = new \DateTime($author->getUpdateAt());\ $date = $authorDate>$articleDate ? $authorDate : $articleDate; $response->setLastModified($date); $response->isNotModified($this->getRequest()); return $response; }
Response::isNotModified() 方法比较请求Request中的If-Modified-Since头和Response中的Last-Modified 头。若是他们相等,Response会被设置一个304状态码。
注意,If-Modified-since 请求头等于最终发送到客户端特定资源Last-Modified头。这就是如何客户端和服务端相互交流决定资源自从它被缓存后是否被更新。
使用校验优化你的代码:
任何缓存策略的主要目的都是减轻应用程序的加载。换句话说,你的应用程序作的越少来返回304 response,越好。Response::isNotModified()方法经过暴露一个简单有效的模式作到了。
public funcation showAction($articleSlug) { //获取最小信息来计算ETag或者Last-Modified值(基于Request,数据是从数据库或者一个键值对存储实例中获取。 $article = //... //建立一个Response带有一个ETag 和/或者 一个Last-Modified 头 $response = new Response(); $response->setETag($article->computeETag()); $response->setLastModified($article->getPublishedAt()); //为给定的Request检查Response没有被修改 if($response->isNotModified($this->getRequest())){ //马上返回304 Response return $response; }else{ //作一些更多的工做-好比获取更多的数据 $comment=//... //或者用你已经开启的$response渲染一个模版 return $this->render('MyBundle:MyController:article.html.twig', array('article'=>$article, 'comments' =>$comments), $response ); } }
当Response没有被修改后,isNotModified()自动设置response的状态码为304,移除response的内容,移除一些不须要为304存在的头。
不一样的回复响应:
到目前为止,咱们已经假设了每一个URI只有一个目标资源的表示。默认状况 下,HTTP缓存经过使用URI的资源做为缓存键被执行。若是两我的请求同一个可缓存资源的URI,第二个用户将获取缓存版本。有时候这些不够,不一样版本 的用一个URI须要被按照一个或者多个请求头的值来被缓存。举个例子,若是当客户端支持你压缩页面时,任何给定的URI都有两种表示:一个是客户端支持压 缩时,一个是不支持时的表示。这时候请求头的Accept-Encoding值将决定使用哪一个。
在这种状况下,咱们须要回复的特定URI缓存一个压缩版本和一个非压缩版本,基于请求的Accept-Encoding值返回它们。这是经过Vary Response头,Vary是一个不一样头用逗号分隔,它的值触发请求资源的不一样表示。
Vary:Accept-Encoding,User-Agent
注意,这个特别的Vary头,将基于URI和Accept-Encoding和User-Agent 请求头为每一个资源的不一样版本进行缓存。
Response对象提供一个干净的接口来管理Vary 头:
// 设置一个vary 头 $response->setVary('Accept-Encoding'); // 设置多个vary头 $response->setVary(array('Accept-Encoding', 'User-Agent'));
setVary()方法须要一个头名字或者一个头名字数组对应不一样的response。
过时和校验:
你固然能够在同一个Response中同时使用校验和过时。由于过时赛过校验,你能够轻易的从它们两个中根据好处作出选择。换句话说,经过同时使用过时和校验,你能够指示缓存服务于缓存的内容,同时后台间隔检查来调查内容是否依然合法。
更多Response方法:
Response类提供了许多和缓存相关的方法。下面是主要的一些:
// 标志Response过时陈旧 $response->expire(); // 强迫response返回一个适合 304 的没有内容的response $response->setNotModified();
另外,跟缓存最相关的HTTP头能够被经过一个单独的方法setCache()设置。
// 经过一个调用设置缓存参数 $response->setCache(array( 'etag' => $etag, 'last_modified' => $date, 'max_age' => 10, 's_maxage' => 10, 'public' => true, // 'private' => true, ));
使用ESI(Edge Side Includes)
网关缓存是一个提升你网站执行效率的很好的途径。可是它们有一个限制:只能缓存整个页面。若是你不想缓存整个页面或者页面的某一部分很动态,你就没那么幸运了。
幸运的是,Symfony2为这些状况提供一个解决方案,基于ESI技术。它容许页面指定的部分和主页比起来有一个不一样的缓存策略。
ESI规范描述标签你能够嵌入到你的页面来和网关缓存交流。Symfony2中只实现了一个标签,include, 由于这是惟一一个能在Akami上下文以外使用的标签。
<html> <body> Some content <!-- 嵌入一个其它页的内容 --> <esi:include src="http://..." /> More content </body> </html>
从这个例子中注意到每一个ESI标签有一个全限定URL。一个ESI标签表示能够经过一个给定的URL获取的一个页面片断。
当请求被处理时,网关缓存从它的缓存或者从背后的应用程序中请求回复获取整个页面。换句话说,网关缓存既从缓存中获取包含的页面片断也会再次从 背后的应用程序中获取回复请求的页面片断。当全部的ESI标签被解析后,网关缓存合并每个ESI内容到一个主页并返回最后的内容到客户端。全部的这一切 都透明的发生在网关缓存级(在你的程序外)。你将看到,若是你选择ESI标签,Symfony2让这包含它们的这一过程几乎不费劲。
在Symfony2中使用ESI
首先,使用ESI须要确认在你的应用程序配置中已经打开。
YAML格式:
# app/config/config.yml framework: # ... esi: { enabled: true }
XML格式:
<!-- app/config/config.xml --> <framework:config ...> <!-- ... --> <framework:esi enabled="true" /> </framework:config>
PHP代码格式:
// app/config/config.php $container->loadFromExtension('framework', array( // ... 'esi' => array('enabled' => true), ));
如今假设咱们有一个页面时相对静态的,除了一个新闻自动收报机在内容的底部。使用ESI,咱们能够缓存新闻自动收报机独立于页面其它部分。
public function indexAction() { $response = $this->render('MyBundle:MyController:index.html.twig'); $response->setSharedMaxAge(600); return $response; }
在该示例中,咱们给全页面缓存周期为10分钟。接下来,经过嵌入一个action让新闻ticker包含到模板中。这是经过render帮助来实现的。由于嵌入的内容来自其它页面,Symfony2使用一个标准的render帮助来配置ESI标签:
Twig格式:
{% render '...:news' with {}, {'standalone': true} %}
PHP格式:
<?php echo $view['actions']->render('...:news', array(), array('standalone' => true)) ?>
经过把standalone设置为true,告诉Symfony2这个action应该被渲染为一个ESI标签。
你可能想知道为何要使用一个helper方法来代替直接写ESI标签。这是由于使用helper让你的应用程序工做即便没有网关缓存被安装。让咱们来看看它是怎样工做的。
当standalone为false时(也是默认值),Symfony2在发送response到客户端以前合并包含的页面内容到一个主页。
可是当standalone为true时,而且若是Symfony2发现它跟支持ESI的网关缓存对话时,它生成一个ESI include标签。
若是没有网关缓存或者网关缓存不支持ESI,Symfony2将只合并包含的标签页面内容到一个主要的像它在standalone为false时所作的同样。
嵌入的action如今能够指定本身的缓存规则了,彻底独立于主页。
public function newsAction() { //... $response->setShareMaxAge(60); }
使用ESI,整个页面缓存将被保持600秒有效,可是新闻组建缓存将只持续60秒。
ESI的一个必备条件是嵌入的action能够经过一个URL被访问,这样网关缓存才能够独立于页面其它部分获取它。固然,一个action不能被经过一个URL访问除非有一个路由指向它。Symfony2 经过一个通用的路由和controller负责这个。
为了ESI包含标签能正常的工做,你必须定义_internal 路由:
YAML格式:
# app/config/routing.yml _internal: resource: "@FrameworkBundle/Resources/config/routing/internal.xml" prefix: /_internal
XML格式:
<!-- app/config/routing.xml --> <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> <import resource="@FrameworkBundle/Resources/config/routing/internal.xml" prefix="/_internal" /> </routes>
PHP代码格式:
// app/config/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection->addCollection($loader->import('@FrameworkBundle/Resources/config/routing/internal.xml', '/_internal')); return $collection;
由于路由容许全部的action经过一个URL被访问,你能够经过使用Symfony2防火墙(容许访问你的反向代理的IP范围)内容保护它。
缓存策略的一大优点是你可让你的应用程序根据动态的须要同时又尽可能的减小触及应用程序。
一旦你开始使用ESI,请记住必定使用s-maxage指令代替max-age。由于浏览器只接受聚合的资源,它不知道子组件,因此它会按照max-age指令缓存整个页面。这是你不但愿它作的。
render helper支持的两外两个有用选项:
alt:用做ESI标签的alt属性,当src找不到时,它容许你指定一个替代URL。
ignore_errors:若是设置为true,一个onerror属性将被添加到ESI,而且属性值设置为continue,在一个失败事件中,网关缓存将只默默的移除ESI标签。
缓存失效:
“计算机科学中有两大难题:缓存失效和命名事物”---Phil Karlton
你永远都不须要失效缓存数据,由于失效早已在HTTP缓存模型中被考虑到了。若是你使用校验,你永远都不须要经过定义校验任何事情;若是你使用 过时并失效某个资源,它意味着你设置一个将来的过时日期。由于在任何类型的反向代理中失效都是一个顶级规范,若是你不担忧失效,你能够在不改变任何应用程 序代码的状况下在反向代理间切换。
其实,全部的反向代理都提供了清除缓存数据的方式,可是你须要尽可能的避免使用它们。最标准的清除给定URL的缓存的方式是经过指定请求的HTTP方法为PURGE 来进行。
下面是如何配置Symfony2的反向代理支持PURGE HTTP方法:
// app/AppCache.php use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; class AppCache extends HttpCache { protected function invalidate(Request $request) { if ('PURGE' !== $request->getMethod()) { return parent::invalidate($request); } $response = new Response(); if (!$this->getStore()->purge($request->getUri())) { $response->setStatusCode(404, 'Not purged'); } else { $response->setStatusCode(200, 'Purged'); } return $response; } }
注意,你必须保护你的PURGE HTTP方法以免随便一我的使用某些方法清除你的缓存数据。
总结:
Symfony2旨在遵循一条被证实了的道路规则:HTTP。 缓存也不例外。掌握Symfony2缓存系统意味着熟悉HTTP缓存模式和有效的使用它们。
这就意味着,你不能只依赖于symfony2文档和代码示例,你必须了解有关HTTP缓存和网关缓存的更宽阔的知识,好比Varnish。