程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> Symfony2框架學習筆記之HTTP Cache用法詳解

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

編輯:PHP綜合

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

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

站在巨人肩膀上的緩存:

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

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

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

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

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

使用網關緩存

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

按照這個思路,緩存會保存被認為是“可緩存的”每一個響應回復。當同樣的請求再次傳來時,該緩存會把自己緩存的響應直接回復給請求客戶端,而完全忽略你的應用程序。這種類型的緩存就是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。

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved