亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Symfony2中文手冊 / HTTP緩存

HTTP緩存

Diff本文源自BOOK,不同于官方現(xiàn)有文檔。本文在某些地方解釋得更深入、更細致。因此我們沒有強行與官方同步。

富網(wǎng)絡(luò)應(yīng)用程序的天然屬性是,它們是動態(tài)的。不管你的程序多有效率,每次請求始終承受著遠遠大過靜態(tài)文件的開銷。

而更多的web程序,并沒有受大的影響。Symfony閃電般快,除非你在做一些超級重載,每一次請求都會很快恢復(fù),而沒有把過多壓力留給服務(wù)器。

但你的網(wǎng)站在成長,過載有可能成為問題。針對通常請求的處理,只應(yīng)完成一次。而這正是緩存鎖定的目標。

緩存于巨人的肩膀 ?

改善一套程序的性能,最有效的方式是緩存頁面的全部輸出,然后無視整個后續(xù)請求。當(dāng)然,對于高動態(tài)網(wǎng)站而言,不可能總是這樣。本章,你將了解Symfony的緩存系統(tǒng)是如何運作的,以及為何這是最佳方案。

Symfony緩存系統(tǒng)與眾不同,因為它依靠的是HTTP specification所定義的HTTP cache之簡單與強大。不同于重新發(fā)明一套緩存方法,Symfony強調(diào)的是定義了web基本通信的標準。一旦你掌握了“HTTP驗證”,以及“緩存models的過期”等基本知識,你已經(jīng)可以去掌握Symfony的緩存系統(tǒng)。

學(xué)習(xí)Symfony緩存的過程,可分為四個步驟:

  1. 網(wǎng)關(guān)緩存(gateway cache),或者反向代理(reverse proxy),是位于你程序前面的獨立層。反向代理,緩存的是響應(yīng),因為它們被你的程序返回;還能在請求到達你的程序之前,通過緩存的響應(yīng)來回應(yīng)請求。Symfony提供了自己的反向代理,但是任何反向代理都可以使用。

  2. HTTP cacheHTTP緩存頭,在你的程序和客戶端之間,被用于同網(wǎng)關(guān)緩存或其他緩存進行通信。Symfony提供了合理的默認配置,以及強大的接口,用于與緩存頭(cache headers)進行互動。

  3. HTTP過期與驗證(expiration and validation),這兩個模型被用于決定緩存的內(nèi)容是否新鮮/fresh(可從cache中復(fù)用),或者是否陳舊/stale(應(yīng)當(dāng)被程序重新生成)

  4. Edge Side Includes(ESI),邊緣端包容允許HTTP cache被用于頁面局部(甚至嵌套片段)的獨立緩存。在ESI的幫助下,你甚至可以“緩存整個頁面60分鐘,但側(cè)邊欄只緩存5分鐘”。

由于HTTP cache并非Symfony專用,有很多相關(guān)文章。如果你對HTTP緩存不太熟,強烈推薦閱讀Ryan Tomayko的緩存能做什么(Things Caches Do)。另一個深度好文是Mark Nottingham的緩存教程(Cache Tutorial)

使用Gateway Cache ?

當(dāng)用HTTP緩存時,cache是完全與你的程序分開的,它居于你的程序與發(fā)動請求的客戶端的之間。

緩存的任務(wù),就是接收客戶端請求,然后把它們再傳回你的程序,跟著推送回客戶端。這里的緩存是程序與瀏覽器之間的“請求-響應(yīng)”通信過程的“中間人”。

隨著時間推移,這些緩存將存儲每一次被認為“可以緩存(cacheable)”的響應(yīng)(參考HTTP緩存介紹)。如果相同的資源被再次請求,cache將發(fā)送緩存了的響應(yīng)至客戶端,完全無視你的程序。

這種類型的緩存即是HTTP gateway cache(網(wǎng)關(guān)緩存),存在于諸如Varnish、反向代理模式下的Squid以及Symfony的反向代理之中。

緩存類型 ?

但是Gateway緩存并非唯一的緩存類型。實際上,你的程序發(fā)送的HTTP緩存頭,被假定于被最多三種方式的緩存所解釋:

  • 瀏覽器緩存(Browser caches):每個瀏覽器都內(nèi)置了自己的本地緩存,用于你點擊“回退”時使用,或者用于圖片和其他assets資源。瀏覽器緩存是私有(private)緩存,因為緩存的資源不能被其他人使用;

  • 代理緩存(Proxy caches):代理,是指共享(shared)緩存,因為很多人可以跟在某個人的后面(來使用)。通常被大公司或ISP所使用,以減低訪問延遲和網(wǎng)絡(luò)流量。

  • 網(wǎng)關(guān)緩存(Gateway caches):類似代理,它也是共享緩存,但卻是在服務(wù)器端。常為網(wǎng)絡(luò)管理員所用,令網(wǎng)站更易升級、更可靠、性能更高。

Gateway caches有時特指反向代理緩存,surrogate caches(代理緩存),甚至HTTP加速器。

當(dāng)緩存的響應(yīng)包含了某個特定用戶的內(nèi)容(比如賬號信息)這種情況被討論時,私有(private)緩存和共享(shared)緩存的重要性與日俱增。

程序的每一次響應(yīng),將會經(jīng)歷前兩種緩存類型中的一種或兩種。這些緩存是在你的(程序)控制之外,卻遵守響應(yīng)中設(shè)置好的HTTP緩存的指令。

Symfony反向代理(Reverse Proxy) ?

Symfony內(nèi)置了用PHP寫的反向代理(也被稱為gateway緩存)。它并非Varnish這種全功能的反向代理緩存,但卻是一個很好的起步。

關(guān)于Varnish設(shè)置的更多細節(jié),參考 如何使用Varnish加速我的網(wǎng)站。

開啟代理很容易:Symfony程序都預(yù)建了一個cache kernel緩存核心(AppCache),它把默認的核心(AppKernel)給打包。這個緩存核心就是 反向代理。

開啟緩存很容易,修改你的前端控制器代碼。你也可以在app_dev.php中做出這些改變,即可為dev環(huán)境添加緩存:

// web/app.phpuse Symfony\Component\HttpFoundation\Request;
// ...$kernel = new AppKernel('prod', false);$kernel->loadClassCache(); 
// add (or uncomment) this new line! / 添加下面新行!
// wrap the default AppKernel with the AppCache one
// 用AppCache打包默認的AppKernel$kernel = new AppCache($kernel); $request = Request::createFromGlobals(); $response = $kernel->handle($request);$response->send(); $kernel->terminate($request, $response);

上面的緩存核心,將立即作為反向代理來運作——從你的程序中緩存響應(yīng),然后把它們返回到客戶端。

如果你正使用framework.http_method_override選項,來從_method參數(shù)中讀取HTTP方法,參考上面鏈接來調(diào)整到你需要的程度。

緩存核心有一個特殊的getLog()方法,返回一個字符串,用以表明緩存層中到底發(fā)生了什么。在開發(fā)環(huán)境下,可以使用它來除錯,或者驗證你的緩存戰(zhàn)略。

1
error_log($kernel->getLog());

AppCache對象有一個合適的默認配置,但是通過覆寫getOptions()方法來設(shè)置一組選項,該對象即可被精細調(diào)整。

// app/AppCache.phpuse 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()方法中進行覆寫,否則debub選項將被自動設(shè)成“被剝離出來的AppKernel”中的debug值。


下面是一些主要選項:

default_ttl

數(shù)值是秒,表達的是當(dāng)響應(yīng)中沒有提供明確的新鮮度信息時,一個緩存入口被認為是fresh的時長。顯式指定Cache-ControlExpires頭,可以覆寫這個值(默認是0)。


private_headers

一組請求頭,在沒有“通過Cache-Control指令(默認是AuthorizationCookie)明確聲明當(dāng)前響應(yīng)是public還是private狀態(tài)”的響應(yīng)中,觸發(fā)“private”Cache-Control行為。


allow_reload

指定客戶端是否可以在請求中包容一個Cache-Control的“no-cache”指令來強制重新加載緩存。設(shè)為true即可遵守RFC2616(默認是false)。


allow_revalidate

指定客戶端是否可以在請求中包容一個來Cache-Control的“max-age=0”來強制重新驗證。設(shè)為true即可遵守RFC2616(默認是false)。


stale_while_revalidate

指定的默認秒數(shù)(以秒為間隔是因為Response的TTL精度是秒),在此期間,盡管緩存在后臺對響應(yīng)正進行重新驗證,但它能夠立即返回一個不新鮮的響應(yīng)(默認值是2);本設(shè)置可被HTTPCache-Control擴展的stale-while-revalidate覆寫(參考RFC 5861)。


stale_if_error

指定的默認秒數(shù)(間隔是秒),在此期間,緩存可以對遇到錯誤的響應(yīng)提供服務(wù)(默認值是60)。本設(shè)置可被HTTPCache-Control擴展的stale-if-error覆寫(參考RFC 5861)。


如果debug被設(shè)為true,Symfony將自動添加一個X-Symfony-Cache頭到響應(yīng)中,里面有關(guān)于緩存命中和丟失的有用信息。

從一個反向代理切換到另一個

在開發(fā)網(wǎng)站時,或者在部署網(wǎng)站到“除了php代碼什么都不能安裝”的共享主機過程中,Symfony的反向代理是個極為好用的工具。但由于是用PHP寫成,它不如用C寫的代理快。這也是為什么強烈推薦你在生產(chǎn)環(huán)境的服務(wù)器上盡可能地使用Vanish或Squid。好消息是,從一個代理服務(wù)器切換到另一個是很容易的,而且過程透明,因為你的程序中并沒有代碼要修改。你可以安心使用Symfony反向代理,日后訪問量增長時可以隨時升級到Varnish。

Symfony反向代理的性能是獨立于程序復(fù)雜程度之外的。這是因為程序內(nèi)核只在“request需要被發(fā)送給它”時才會啟動。

令你的響應(yīng)成為HTTP緩存 ?

為了利用可用的緩存層,你的程序應(yīng)該與以下信息進行通信:1、哪些響應(yīng)可被緩存。2、能夠決定緩存“何時/如何變成不新鮮”的規(guī)則。

記得,“HTTP”就是一種語言(簡單文本)而已,被客戶端和和服務(wù)器用來進行相互通信之用。而HTTP緩存就是這種語言的一部分,允許客戶端和服務(wù)器交換關(guān)于緩存的信息。

HTTP指定了以下四種用于響應(yīng)的緩存頭:

  • Cache-Control

  • Expires

  • ETag

  • Last-Modified

其中最為重要和功能最強的當(dāng)屬Cache-Control頭,它可說是多種緩存信息的集合。

每種頭都在HTTP Expiration,Validation和Invalidation小節(jié)中進行了詳解。

Cache-Control頭 ?

Cache-Control頭是特殊的,它包含不止一條,而是很多條和響應(yīng)的緩存能力相關(guān)的信息。每種信息被以英文逗號分隔開來:

Cache-Control: private, max-age=0, must-revalidate
 
Cache-Control: max-age=3600, must-revalidate

Symfony提供了一個關(guān)于Cache-Control頭的抽象層,以便令它的創(chuàng)建更加易于管理:

// ... use Symfony\Component\HttpFoundation\Response; $response = new Response();
// mark the response as either public or private 標記響應(yīng)是公有還是私有$response->setPublic();$response->setPrivate();
// set the private or shared max age 設(shè)置私有或公有的最大周期$response->setMaxAge(600);$response->setSharedMaxAge(600); 
// set a custom Cache-Control directive 設(shè)置一個自定義Cache-Control命令$response->headers->addCacheControlDirective('must-revalidate', true)

如果你要為控制器中不同的action設(shè)置緩存頭,你也許需要看看FOSHttpCacheBundle。它提供了一種基于URL模式匹配和其他請求屬性的方式來定義緩存頭。

Public響應(yīng)和Private響應(yīng) ?

不管是gateway還是proxy緩存,都被認為是“shared”共享緩存,因為緩存內(nèi)容被更多用戶分享。如果一個“特定用戶專有”響應(yīng)被錯誤地置于共享緩存中,它可能在后面的時間里被返回給多位不同用戶。試想你的賬號信息被緩存,然后發(fā)送給所有后續(xù)請求了自己賬號頁面的用戶是個什么場面!

為應(yīng)對這種情形,每一個響應(yīng)應(yīng)當(dāng)被設(shè)為public或private:

public

指示響應(yīng)應(yīng)該被同時緩存為public和private緩存。


private

指示所有或部分響應(yīng)信息僅針對某一用戶,因此禁止緩存為public緩存。


Symfony保守的設(shè)置每一次響應(yīng)為private。為了利用好共享緩存(比如Symfony反向代理),響應(yīng)必須顯式設(shè)定為public。

安全方法(Safe Method) ?

HTTP緩存只工作在“安全”HTTP方法下(比如GET或HEAD)。所謂安全,是指你在對請求提供服務(wù)時(諸如記錄日志,處理緩存信息等)永遠不能改變服務(wù)器上的程序狀態(tài)。這就產(chǎn)生兩個極為有說服力的重要結(jié)論:

  • 你永遠不應(yīng)該在GET或HEAD請求的響應(yīng)中改變程序狀態(tài)。就算你不使用gateway cache,然而代理緩存的本質(zhì)是,任何GET或HEAD請求,可能或并沒有真正hit到你的服務(wù)器;

  • 不要預(yù)期對PUT、POST或DELETE方法進行緩存。這些方法意味著被用于你的程序狀態(tài)發(fā)生改變時(比如刪除一篇博客)。緩存它們將阻止特定的請求命中或改變你的程序。

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

HTTP1.1允許默認緩存任何內(nèi)容,除非顯式指定了Cache-Control頭。實踐中,多數(shù)緩存在請求中包含cookie時、包含authorization頭時、使用了一個非安全方法時(比如PUT、POST或DELETE)或當(dāng)響應(yīng)有一個重定向狀態(tài)碼時,什么也不做。

當(dāng)開發(fā)者在響應(yīng)頭中什么也沒設(shè)置時,Symfony依據(jù)以下規(guī)則,自動設(shè)置了有意義的而且是偏保守的Cache-Header頭。

  • 如果沒有緩存頭信息被定義(Cache-Control、Expires、ETagLast-Modified),Cache-Control將被設(shè)為no-cache,代表響應(yīng)將不被緩存;

  • 如果Cache-Control是空(但是另外一個緩存頭有被設(shè)置),其值將被設(shè)為private, must-revalidate;

  • 但是如果至少有一個Cache-Control指令被設(shè)置,而且沒有publicprivate指令被顯式添加的話,Symfony會自動添加private指令(除了當(dāng)s-maxage被設(shè)置時)

HTTP Expiration,Validation和Invalidation ?

HTTP協(xié)議定義了兩種緩存模型:

  • 利用expiration model(過期模型),通過包容Cache-Control頭和/或Expires頭,即可直接指定一個響應(yīng)應(yīng)該被認為“新鮮”的時長。緩存能夠理解過期時間,不再制造相同請求,直到該緩存版本抵達過期時間,而且變得“不新鮮(stale)”。

  • 當(dāng)頁面是真動態(tài)時(展現(xiàn)層經(jīng)常改變),則validation model(驗證模型)的使用就十分有必要。利用這個模型,緩存把響應(yīng)存儲起來,但會在每次請求時向服務(wù)器“提問”——是否緩存了的響應(yīng)仍然有效?程序使用了一個獨立的響應(yīng)識別器(即Etag頭)和/或一個時間戳(即Last-Modified頭),來檢查當(dāng)前頁面自被緩存之后,是否發(fā)生了改變。

理解HTTP Specification

HTTP specification定義了一種簡單但卻強大的語言,可以令客戶端和服務(wù)器進行通信。作為web開發(fā)者,HTTP specification所擁有的request-response model(“請求-響應(yīng)”模型)將支配你的緩存工作。不幸的是,HTTP協(xié)議的真正文檔:RFC2616,是難以讀懂的。

不過有一個正在進行中的HTTP Bis要覆寫RFC 2616。它并不描述新版本的HTTP,更多的是對原有HTTP協(xié)議進行疏理。文檔的組織結(jié)構(gòu)也隨著HTTP協(xié)議被分為七個部分而有所改進;關(guān)于HTTP caching的每一部分,都可以在以下兩個獨立章節(jié)找到(P4 - Conditional RequestsP6 - Caching: Browser and intermediary caches)。

作為一名web開發(fā)者,你被我們Symfony官方團隊 最強烈力勸 來閱讀HTTP協(xié)議相關(guān)內(nèi)容。它是如此明晰與強大——哪怕是在它被創(chuàng)造出來的10年之后——Http Specification是無價的。我們特別提醒您,千萬別對這些協(xié)議的表象敷衍了事——其內(nèi)容之美麗,百千萬億倍于其封面。

Expiration(過期) ?

expiration model,是兩個緩存模型里效率更高、更直接的一個,因此應(yīng)該被盡可能多地使用。當(dāng)一個響應(yīng)通過expiration被緩存時,緩存將保存響應(yīng),并且在過期之前直接返回它,而毋須命中程序。

過期模型,可以通過以下幾乎一樣的兩種HTTP頭之一來實現(xiàn):ExpiresCache-Control

使用Expires頭控制過期 ?

根據(jù)HTTP specification,“Expires頭字段將在response被認為是stale之后給出date/time?!?。這里的Expires頭可以被設(shè)為Response方法:setExpires()。它使用DateTime實例作為參數(shù):

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

該響應(yīng)的HTTP頭信息類似這種:

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

setExpires()方法將自動轉(zhuǎn)換日期為GMT時區(qū),因為這是HTTP specification的要求。

注意,在HTTP 1.1版之前,并不需要原始服務(wù)器來發(fā)送Date頭。因此,緩存(比如瀏覽器的)就需要本地時鐘來評估Expires頭,進而令緩存周期的計算因時間傾斜而變得脆弱不堪。另外一個Expires頭限制是,正如HTTP協(xié)議中所描述的,“HTTP/1.1 不得發(fā)送Expires的日期超過一年?!?/p>

使用Cache-Control頭控制過期 ?

因為Expires頭的限制,多數(shù)情況下,你應(yīng)該使用Cache-Control頭來替代。記得,Cache-Control頭被用于多種不同的緩存指令。例如,max-ages-maxage。第一個用于全部緩存,而第二個僅在共享緩存時用到。

// Sets the number of seconds after which the response
// should no longer be considered fresh// 設(shè)置“響應(yīng)過期”的秒數(shù)$response->setMaxAge(600);
 // Same as above but only for shared caches
// 同上,但僅用于共享緩存$response->setSharedMaxAge(600);

Cache-Control頭一般是下述格式(但有時也會有其他指令):

1
Cache-Control: max-age=600, s-maxage=600

過期和驗證(Expiration and Validation) ?

你當(dāng)然可以對同一個Response同時使用validation和expiration。因為expiration的優(yōu)勢大過validation,你能很容易地從兩個世界中好的一面受益。也就是說,同時使用過期和驗證,你可以命令緩存來服務(wù)于已緩存的內(nèi)容,同時還能在某些區(qū)間(expiration)向后檢查以確認緩存內(nèi)容仍然有效。

你也可以通過annotation來為expiration和validation去定義HTTP緩存頭。參考FrameworkExtraBundle文檔。

更多Response方法 ?

Response類提供了很多方法以應(yīng)對緩存。下面是幾個特別有用的:

// Marks the Response stale 標記響應(yīng)過期$response->expire(); 
// Force the response to return a proper 304 response with no content
// 強制響應(yīng)返回一個沒有內(nèi)容的恰當(dāng)?shù)?04響應(yīng)$response->setNotModified();

另外,多數(shù)與緩存相關(guān)的HTTP頭可以單獨使用setCache()方法來完成設(shè)置:

// Set cache settings in one call$response->setCache(array(
    'etag'          => $etag,
    'last_modified' => $date,
    'max_age'       => 10,
    's_maxage'      => 10,
    'public'        => true,
    // 'private'    => true,
    ));

總結(jié) ?

Symfony的設(shè)計思想即是遵循業(yè)界公認標準:HTTP。緩存功能也不例外。掌握Symfony的緩存系統(tǒng)意味著你已然熟悉了HTTP cache模型并且能夠高效地使用它。換句話說,毋須依賴Symfony文檔和例程,你可以馳騁于HTTP caching和以Varnish為代表的gateway caches的世界。