亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Symfony2框架學習筆記之HTTP Cache用法詳解

 更新時間:2016年03月18日 09:02:54   作者:Seekr  
這篇文章主要介紹了Symfony2框架HTTP Cache用法,結合實例形式分析了Symfony框架HTTP緩存的相關使用技巧,需要的朋友可以參考下

本文實例講述了Symfony2框架HTTP Cache用法。分享給大家供大家參考,具體如下:

富web應用程序的本質意味著它們的動態(tài)。無論你的應用程序多么有效率,每個請求比起靜態(tài)文件來說總會存在很多的耗費。對于大多數(shù)web程序來說,這沒什么。 Symfony2非常的輕快,無論你做些嚴重超載的請求,每個請求將會得到很快的回復,而不會對你的服務器造成壓力。但是隨著你站點的成長,負載將成為一個嚴重的問題。對每個請求處理應該只被正常執(zhí)行一次。這就是緩存真正要達成的目標。

站在巨人肩膀上的緩存:

提高一個應用程序執(zhí)行效率的最有效方法是緩存一個頁面的所有輸出然后讓后續(xù)的請求繞開整個應用程序。當然,這對于高動態(tài)性的站點來說并不是總是可能的。Symfony2 緩存系統(tǒng)是比較特別的,因為它依賴于在HTTP規(guī)范中定義的簡單強大的HTTP cache。沒有重新發(fā)明新的緩存方法,Symfony2 擁抱在web上定義基礎交流的標準。一旦你理解了基礎的HTTP校驗和過期緩存模式,你就會完全掌握了Symfony2的緩存系統(tǒng)。

第一步:一個網(wǎng)關緩存(gateway cache),或者反向代理。是一個坐在你應用程序前面的對立的層。反向代理緩存來自于你應用程序的響應并使用這些緩存響應在某些請求到達你應用程序之前來回復它們。 Symfony2提供了自己的反向代理,也可以使用其它任何的反向代理。

第二步:HTTP緩存 (HTTP cache)頭用于和網(wǎng)關緩存以及任何其位于客戶和你的應用程序之間的其它緩存交流。Symfony2 提供了和緩存頭交互的預設行為和強大接口。

第三步:HTTP 超時和校驗時用于決定一個緩存內容是否新鮮和陳舊的兩種模式。

第四步:ESI(Edge Side Includes)允許HTTP緩存被用于獨立緩存頁面片段(甚至是嵌套片段)。使用ESI,你甚至可以緩存一個完整的頁面60分鐘。但一個嵌入式邊欄緩存只有5分鐘。

使用網(wǎng)關緩存

當使用HTTP緩存時,緩存是跟你的應用程序完全分離的,它位于你的請求客戶端和應用程序之間。該緩存的工作就是從客戶端接收請求并把它們傳遞回你的應用程序。同時它也將接收從你的應用程序返回的響應并把它轉給客戶端。可以說它是你的應用程序和請求客戶端之間請求-響應交互的中間人。

按照這個思路,緩存會保存被認為是“可緩存的”每一個響應回復。當同樣的請求再次傳來時,該緩存會把自己緩存的響應直接回復給請求客戶端,而完全忽略你的應用程序。這種類型的緩存就是HTTP網(wǎng)關緩存。目前有很多這類緩存,比如Varnish,Squid in reverse proxy mode和Symfony2 反向代理等。

緩存類型

一個網(wǎng)關緩存不是緩存的唯一類型。事實上,有三種不同類型的緩存會截獲并使用你的應用程序發(fā)出的HTTP緩存頭。它們是:

瀏覽器緩存(Browser caches):瀏覽器擁有自己的本地緩存,這對你單擊"前一步"或者查看圖片和其它網(wǎng)絡資產時起到了主要作用。

代理緩存(Proxy caches):一個代理緩存是一個多人位于一人之后的共享的緩存。它們大多是一些大公司或者ISP安裝用來減少延遲和網(wǎng)絡阻塞的。

網(wǎng)關緩存(Gateway caches):像一個代理,也是一個共享緩存但是是位于服務器端的。一般是網(wǎng)絡管理員安裝它們,它使得網(wǎng)站更具可伸縮性,可靠性和高效性。網(wǎng)關緩存有時候被稱為反向代理緩存,代理緩存,更或者是HTTP加速器。

Symfony2 反向代理

Symfony2擁有一個用PHP編寫的反向代理(也叫做網(wǎng)關緩存)。開啟它后,來自你應用程序的可緩存的響應回復將會開始被立刻緩存。安裝它相也當容易。每一個新的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();

緩存內核會立刻扮演一個反向代理的角色,緩存來自你應用程序的回復把它們發(fā)回給請求客戶端。

注意,該緩存內核有一個特別的getLog()方法返回一個能夠表示在緩存層發(fā)生了什么的字符串。

可以在開發(fā)環(huán)境中來調試和校驗你的緩存策略。

error_log($kernel->getLog());

AppCache 對象是一個合理的默認配置,當然你也可以通過重寫getOptions()方法來設置可選項對它進行調優(yōu)。

// 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: 當沒有顯式的刷新信息在回復中提供時,一個緩沖實體應該被認為是新鮮的時間秒數(shù)。顯式的設置Cache-Control 或者 Expires 頭會覆蓋這個參數(shù)值。默認值為0。
private_headers:請求頭組,它在回復上觸發(fā)"private" Cache-Control 行為,無論回復是通過Cache-Control 指令顯式的聲明是public還是private 。默認為Authorization和Cookie。
allow_reload: 指定是否允許客戶端通過在請求中指定Cache-Control的"no-cache"指令來強迫緩存重新加載。設置它為true時符合RFC2616規(guī)范。默認值為false。
allow_revalidate:指定是否允許客戶端通過在請求中指定Cache-Control的"max-age=0"指令來強迫緩存重新校驗。設置它為true時符合RFC2616規(guī)范。默認值為false。
stale_while_revalidate:用于指定一個默認秒數(shù)(間隔是秒因為回復TTL精度是1秒),在期間緩存還在后臺進行重新校驗時可以立刻返回一個陳舊的回復(默認是2);該設置會被stale-while-revalidate HTTP Cache-Control擴展重寫(RFC 5861)。
stale_if_error: 指定一個默認秒數(shù)(間隔是秒)在這期間緩存可以提供一個陳舊的回復當遇到一個錯誤時。默認值為60。該設置會被stale-if-error HTTP Cache-Contorl 擴展重寫(RFC5861)

如果debug設置為true,Symfony2 會自動添加一個X-Symfony-Cache 頭到回復保存著關于緩存點擊和丟失的信息。

從一個反向代理到另一個的轉換:

Symfony2反向代理是一個在開發(fā)你的站點或者部署你的站點到一個共享主機而你無法安裝任何除PHP代碼以外的東西時的非常有用的工具。但是因為使用PHP編寫,它不能跟用C寫成的反向代理那樣快速。這就是為什么我們推薦使用Varnish或者Squid到你的運營服務器上的原因。好消息是從一個代理服務器到另外一個替換很容易,簡單的不用你修改任何程序代碼。你可以開始時使用Symfony2的反向代理等到了阻塞增加時升級到Varnish。

注意:Symfony2 反向代理執(zhí)行效率獨立于應用程序的復雜性。因為應用程序核心僅僅在請求需要被轉發(fā)到它時才被啟動。

HTTP緩存說明:

為了發(fā)揮可用緩存層的優(yōu)勢,你的應用程序必須能傳達它的哪個回復可以被緩存,什么時候/怎樣 緩存會變成陳舊的規(guī)則。這些是通過在回復(response)上設置HTTP 緩存頭來實現(xiàn)的。

記住,"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頭的抽象,使它的創(chuàng)建更加可控。

$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

網(wǎng)關緩存和代理緩存都被認為是“共享”緩存,因為它們緩存的內容是被多用戶共享的。如果一個特定用戶的回復曾被錯誤的存儲到共享緩存中,它以后可能被返回給無數(shù)的不用用戶。想象一下,如果你的賬戶信息被緩存然后返回給每一個后來請求他們自己賬戶頁面的用戶。要處理這種情況,每個回復可能都要設置時public還是private。

public 說明給回復可能被private和共享的緩存保存。
private 說明所有的或者部分的回復信息時給一個單獨用戶的,所以不能緩存到共享緩存中。

Symfony 謹慎地默認每個回復為private。 要使用共享緩存的優(yōu)點(比如Symfony2反向代理),回復必須被顯式的設置為public。

安全方法:

HTTP緩存僅僅為安全方法工作(比如GET和HEAD)。要安全意味著當它為某個請求服務時從來不會改變服務器上應用程序的狀態(tài)。(當然你可以寫日志信息,緩存數(shù)據(jù)等)。這里有兩個很合理的后果(consequences):

當你的應用程序回復一個GET或者HEAD請求時,你絕對不會改變你應用程序的狀態(tài)。即使你不用網(wǎng)關緩存,代理緩存的存在意味著任何GET和HEAD請求可能會或者可能不會真的達到你的服務器。

不要期望PUT,POST或者DELETE方法被緩存。這些方法被使用意味著你應用程序狀態(tài)的改變。緩存它們將阻止某種請求訪問或者改變你的應用程序。

緩存規(guī)則和默認設置

HTTP 1.1 默認情況下允許緩存任何事情除非有一個顯式的Cache-Control頭。實踐中,大多數(shù)緩存當請求有cookie,一個授權頭,使用一個非安全的方法(比如PUT,POST,DELETE)或者當請求有一個重定向代碼時,不會進行任何緩存活動。

當開發(fā)者沒有做任何設置時,Symfony2 會自動按照下面的規(guī)則設置一個合理的比較保守的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規(guī)范定義了兩個緩存模型:
過期模型,你只需要通過包含一個Cache-Control和/或者一個Expires頭來指定一個Response應該多長時間被考慮“新鮮”問題。緩存理解過期將不再讓相同的請求回復,直到緩存的版本達到它過期時間成為“stale"陳舊。

校驗模型,當頁面時真正的動態(tài)頁面時(他們的展現(xiàn)經(jīng)常變化),校驗模型就經(jīng)常需要了。這種模型,緩存存儲response,但是要求服務對每個請求是否緩存response依然進行校驗。

應用程序使用唯一的response 標示符(ETag 頭) 和/或者 時間戳(Last-Modified 頭)來檢查頁面自從被緩存后是否放生了變化。

這兩個模型的目標是通過依靠一個緩存存儲并返回"新鮮" response,使得應用程序從不生成相同的response兩次。

過期:

過期模型是在這兩個模型中是更加有效和簡單明確的模型,它應該在任何時候都有被使用的可能。當一個response使用一過期方式被緩存,緩存將存儲response并為請求直接返回它而不去訪問應用程序,直到它過期。

過期模型可以被熟練的使用一兩個,幾乎相同的,HTTP頭:比如 Expires或cache - control。

過期和Expires 頭

根據(jù)HTTP規(guī)范,Expires頭字段提供一個日期/時間,過了這個日期或時間后它的response就被認為是陳舊的了。Expires頭可以被Response的setExpires()方法設置。它要求一個DateTime實例作為輸入?yún)?shù)。

$date = new DateTime();
$date->modify('+600 seconds');
$response->setExpires($date);

生成的HTTP頭的結果如下:

Expires: Thu, 01 Mar 2011 16:00:00 GMT

注意,因為規(guī)范的需要setExprise()方法會自動把日期轉換為GMT時區(qū)。

我們注意到在HTTP規(guī)范1.1版之前,源服務不需要發(fā)送一個Date頭。 因此緩存(比如瀏覽器)可能需要依靠它本地的始終來評估Expires頭,造成計算生命周期時時鐘偏差。 Expires頭的另一個限制是規(guī)范規(guī)定:"HTTP/1.1服務不應該發(fā)送Expires日期未來超過一年。"

過期和Cache-Control 頭

因為Expires頭的限制,大多時候,你應該采用Cache-Control頭來替代它。回想一下,Cache-Control頭是用來指定多個不同緩存指令的。對于過期來說,有兩個指令,max-age 和 s-maxage。第一個被所有的緩存使用,然而第二個僅僅被用于共享緩存。

// 設置一個秒數(shù),過了這個秒數(shù)后response就被認為是陳舊的了。
$response->setMaxAge(600);
// 同上,但是只用于共享緩存。
$response->setSharedMaxAge(600);
Cache-Control頭將使用如下格式(它可能還有其它指令):
Cache-Control: max-age=600, s-maxage=600

校驗:

一旦底層數(shù)據(jù)發(fā)生變化需要立刻對緩存資源進行更新時,過期模型就顯得力不從心了。在過期模型下,應用程序不會被要求返回更新的response直到緩存最后過期變?yōu)殛惻f內容以后。

校驗模型解決了這個問題。在校驗模型下,緩存持續(xù)保存response。不同的是,對每一個請求request,緩存都詢問應用程序緩存的response是否依然有效。如果緩存仍然有效,你的應用程序應該返回一個304狀態(tài)碼和一個空內容。這告訴緩存它可以為請求用戶返回它緩存的response。

在這個模型下,你主要節(jié)省了帶寬因為描述不會發(fā)送兩次到相同的客戶端(而是發(fā)送一個304回復代替)。但是,如果你仔細設計你的應用程序,你可能能忍受304 response需要的最小數(shù)據(jù)并節(jié)省CPU。

304狀態(tài)碼意味著沒有修改。它很重要因為它沒有包含整整的被請求內容,而只是一個輕量級的導向集,它告訴緩存它應該使用它現(xiàn)在保存的版本回復請求。跟過期類似,也有兩個不同的HTTP頭可以被用來實現(xiàn)校驗模型: ETag和Last-Modifed

校驗和ETag頭

ETag頭是一個字符串(也叫"entity-tag")它是目標資源一個表現(xiàn)的唯一標識。它完全由你的應用程序來生成和設置。 比如,如果 /about 資源被緩存保存時取決于日期和你應用程序的返回內容。一個ETag像一個手印,被用來快速的比較一個資源的兩個不同版本是否等效。
像手印,同一個資源的所有表示形式中每個ETag必須是唯一的。讓我們來簡單實現(xiàn)一個生成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一起發(fā)送的ETag與Response上的ETag進行比較。如果兩個匹配,方法自動設置Response狀態(tài)碼為304。

這個算法非常簡單也非常通用,但是你需要在能計算ETag之前創(chuàng)建一個完整的Response,校驗模型是次優(yōu)選擇。換句話說,它節(jié)省了帶寬,單沒有節(jié)省CPU利用。  

Symfony2還通過向setETag()方法傳入true作為第二個參數(shù),來支持弱ETag。

校驗和Last-Modified 頭

Last-Modified頭是校驗模型的第二種形式。根據(jù)HTTP規(guī)范,”Last-Modified 頭字段指定日期和時間,在這個時間源服務器相信該表現(xiàn)是最后被修改版?!?br /> 換句話說,應用程序決定基于自動緩存內容被緩存后是否被更新過來判斷緩存的內容是否要被更新過。舉個例子,你可以使用最新更新日期為所有需要計算資源表現(xiàn)的對象作為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狀態(tài)碼。

注意,If-Modified-since 請求頭等于最終發(fā)送到客戶端特定資源Last-Modified頭。這就是如何客戶端和服務端相互交流決定資源自從它被緩存后是否被更新。

使用校驗優(yōu)化你的代碼:

任何緩存策略的主要目的都是減輕應用程序的加載。換句話說,你的應用程序做的越少來返回304 response,越好。Response::isNotModified()方法通過暴露一個簡單有效的模式做到了。

public funcation showAction($articleSlug)
{
  //獲取最小信息來計算ETag或者Last-Modified值(基于Request,數(shù)據(jù)是從數(shù)據(jù)庫或者一個鍵值對存儲實例中獲取。
  $article = //...
  //創(chuàng)建一個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{
    //做一些更多的工作-比如獲取更多的數(shù)據(jù)
    $comment=//...
    //或者用你已經(jīng)開啟的$response渲染一個模版
    return $this->render('MyBundle:MyController:article.html.twig',
        array('article'=>$article, 'comments' =>$comments),
        $response
    );
  }
}

當Response沒有被修改后,isNotModified()自動設置response的狀態(tài)碼為304,移除response的內容,移除一些不需要為304存在的頭。

不同的回復響應:

到目前為止,我們已經(jīng)假設了每個URI只有一個目標資源的表示。默認情況下,HTTP緩存通過使用URI的資源作為緩存鍵被執(zhí)行。如果兩個人請求同一個可緩存資源的URI,第二個用戶將獲取緩存版本。有時候這些不夠,不同版本的用一個URI需要被按照一個或者多個請求頭的值來被緩存。舉個例子,如果當客戶端支持你壓縮頁面時,任何給定的URI都有兩種表示:一個是客戶端支持壓縮時,一個是不支持時的表示。這時候請求頭的Accept-Encoding值將決定使用哪個。

在這種情況下,我們需要回復的特定URI緩存一個壓縮版本和一個非壓縮版本,基于請求的Accept-Encoding值返回它們。這是通過Vary Response頭,Vary是一個不同頭用逗號分隔,它的值觸發(fā)請求資源的不同表示。

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()方法需要一個頭名字或者一個頭名字數(shù)組對應不同的response。

過期和校驗:

你當然可以在同一個Response中同時使用校驗和過期。因為過期勝過校驗,你可以輕易的從它們兩個中根據(jù)好處做出選擇。換句話說,通過同時使用過期和校驗,你可以指示緩存服務于緩存的內容,同時后臺間隔檢查來調查內容是否依然合法。

更多Response方法:

Response類提供了許多和緩存相關的方法。下面是主要的一些:

// 標志Response過期陳舊
$response->expire();
// 強迫response返回一個適合 304 的沒有內容的response
$response->setNotModified();

另外,跟緩存最相關的HTTP頭可以被通過一個單獨的方法setCache()設置。

// 通過一個調用設置緩存參數(shù)
$response->setCache(array(
  'etag'     => $etag,
  'last_modified' => $date,
  'max_age'    => 10,
  's_maxage'   => 10,
  'public'    => true,
  // 'private'  => true,
));

使用ESI(Edge Side Includes)

網(wǎng)關緩存是一個提高你網(wǎng)站執(zhí)行效率的很好的途徑。但是它們有一個限制:只能緩存整個頁面。如果你不想緩存整個頁面或者頁面的某一部分很動態(tài),你就沒那么幸運了。

幸運的是,Symfony2為這些情況提供一個解決方案,基于ESI技術。它允許頁面指定的部分和主頁比起來有一個不同的緩存策略。

ESI規(guī)范描述標簽你可以嵌入到你的頁面來和網(wǎng)關緩存交流。Symfony2中只實現(xiàn)了一個標簽,include, 因為這是唯一一個能在Akami上下文之外使用的標簽。

<html>
  <body>
    Some content
    <!-- 嵌入一個其它頁的內容 -->
    <esi:include src="http://..." />
    More content
  </body>
</html>

從這個例子中注意到每個ESI標簽有一個全限定URL。一個ESI標簽表示可以通過一個給定的URL獲取的一個頁面片段。

當請求被處理時,網(wǎng)關緩存從它的緩存或者從背后的應用程序中請求回復獲取整個頁面。換句話說,網(wǎng)關緩存既從緩存中獲取包含的頁面片段也會再次從背后的應用程序中獲取回復請求的頁面片段。當所有的ESI標簽被解析后,網(wǎng)關緩存合并每一個ESI內容到一個主頁并返回最后的內容到客戶端。所有的這一切都透明的發(fā)生在網(wǎng)關緩存級(在你的程序外)。你將看到,如果你選擇ESI標簽,Symfony2讓這包含它們的這一過程幾乎不費勁。

在Symfony2中使用ESI

首先,使用ESI需要確認在你的應用程序配置中已經(jīng)打開。

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),
));

現(xiàn)在假設我們有一個頁面時相對靜態(tài)的,除了一個新聞自動收報機在內容的底部。使用ESI,我們可以緩存新聞自動收報機獨立于頁面其它部分。

public function indexAction()
{
  $response = $this->render('MyBundle:MyController:index.html.twig');
  $response->setSharedMaxAge(600);
  return $response;
}

在該示例中,我們給全頁面緩存周期為10分鐘。接下來,通過嵌入一個action讓新聞ticker包含到模板中。這是通過render幫助來實現(xiàn)的。因為嵌入的內容來自其它頁面,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讓你的應用程序工作即使沒有網(wǎng)關緩存被安裝。讓我們來看看它是怎樣工作的。

當standalone為false時(也是默認值),Symfony2在發(fā)送response到客戶端之前合并包含的頁面內容到一個主頁。

但是當standalone為true時,并且如果Symfony2發(fā)現(xiàn)它跟支持ESI的網(wǎng)關緩存對話時,它生成一個ESI include標簽。

如果沒有網(wǎng)關緩存或者網(wǎng)關緩存不支持ESI,Symfony2將只合并包含的標簽頁面內容到一個主要的像它在standalone為false時所做的一樣。

嵌入的action現(xiàn)在可以指定自己的緩存規(guī)則了,完全獨立于主頁。

public function newsAction()
{
  //...
  $response->setShareMaxAge(60);
}

使用ESI,整個頁面緩存將被保持600秒有效,但是新聞組建緩存將只持續(xù)60秒。

ESI的一個必備條件是嵌入的action可以通過一個URL被訪問,這樣網(wǎng)關緩存才可以獨立于頁面其它部分獲取它。當然,一個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范圍)內容保護它。

緩存策略的一大優(yōu)勢是你可以讓你的應用程序根據(jù)動態(tài)的需要同時又盡量的減少觸及應用程序。

一旦你開始使用ESI,請記住一定使用s-maxage指令代替max-age。因為瀏覽器只接受聚合的資源,它不知道子組件,所以它會按照max-age指令緩存整個頁面。這是你不希望它做的。

render helper支持的兩外兩個有用選項:
alt:用作ESI標簽的alt屬性,當src找不到時,它允許你指定一個替代URL。
ignore_errors:如果設置為true,一個onerror屬性將被添加到ESI,并且屬性值設置為continue,在一個失敗事件中,網(wǎng)關緩存將只默默的移除ESI標簽。

緩存失效:

“計算機科學中有兩大難題:緩存失效和命名事物”---Phil Karlton

你永遠都不需要失效緩存數(shù)據(jù),因為失效早已在HTTP緩存模型中被考慮到了。如果你使用校驗,你永遠都不需要通過定義校驗任何事情;如果你使用過期并失效某個資源,它意味著你設置一個未來的過期日期。因為在任何類型的反向代理中失效都是一個頂級規(guī)范,如果你不擔心失效,你可以在不改變任何應用程序代碼的情況下在反向代理間切換。

其實,所有的反向代理都提供了清除緩存數(shù)據(jù)的方式,但是你需要盡量的避免使用它們。最標準的清除給定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方法以避免隨便一個人使用某些方法清除你的緩存數(shù)據(jù)。

總結:

Symfony2旨在遵循一條被證明了的道路規(guī)則:HTTP。 緩存也不例外。掌握Symfony2緩存系統(tǒng)意味著熟悉HTTP緩存模式和有效的使用它們。

這就意味著,你不能只依賴于symfony2文檔和代碼示例,你必須了解有關HTTP緩存和網(wǎng)關緩存的更寬闊的知識,比如Varnish。

希望本文所述對大家基于Symfony框架的PHP程序設計有所幫助。

相關文章

最新評論