?
? ????? PHP ??? ???? ??? ?? ??
除了前面章節(jié)講到的服務(wù)器端緩存外, Web 應(yīng)用還可以利用客戶(hù)端緩存去節(jié)省相同頁(yè)面內(nèi)容的生成和傳輸時(shí)間。
通過(guò)配置 yii\filters\HttpCache 過(guò)濾器,控制器操作渲染的內(nèi)容就能緩存在客戶(hù)端。yii\filters\HttpCache 過(guò)濾器僅對(duì)?GET
?和?HEAD
?請(qǐng)求生效,它能為這些請(qǐng)求設(shè)置三種與緩存有關(guān)的 HTTP 頭。
Last-Modified
?頭Last-Modified
?頭使用時(shí)間戳標(biāo)明頁(yè)面自上次客戶(hù)端緩存后是否被修改過(guò)。
通過(guò)配置 yii\filters\HttpCache::lastModified 屬性向客戶(hù)端發(fā)送?Last-Modified
?頭。該屬性的值應(yīng)該為 PHP callable 類(lèi)型,返回的是頁(yè)面修改時(shí)的 Unix 時(shí)間戳。該 callable 的參數(shù)和返回值應(yīng)該如下:
function ($action, $params)
以下是使用?Last-Modified
?頭的示例:
public function behaviors(){
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index'],
'lastModified' => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from('post')->max('updated_at');
},
],
];
}
上述代碼表明 HTTP 緩存只在?index
?操作時(shí)啟用。它會(huì)基于頁(yè)面最后修改時(shí)間生成一個(gè)?Last-Modified
?HTTP 頭。當(dāng)瀏覽器第一次訪(fǎng)問(wèn)index
?頁(yè)時(shí),服務(wù)器將會(huì)生成頁(yè)面并發(fā)送至客戶(hù)端瀏覽器。之后客戶(hù)端瀏覽器在頁(yè)面沒(méi)被修改期間訪(fǎng)問(wèn)該頁(yè),服務(wù)器將不會(huì)重新生成頁(yè)面,瀏覽器會(huì)使用之前客戶(hù)端緩存下來(lái)的內(nèi)容。因此服務(wù)端渲染和內(nèi)容傳輸都將省去。
ETag
?頭“Entity Tag”(實(shí)體標(biāo)簽,簡(jiǎn)稱(chēng) ETag)使用一個(gè)哈希值表示頁(yè)面內(nèi)容。如果頁(yè)面被修改過(guò),哈希值也會(huì)隨之改變。通過(guò)對(duì)比客戶(hù)端的哈希值和服務(wù)器端生成的哈希值,瀏覽器就能判斷頁(yè)面是否被修改過(guò),進(jìn)而決定是否應(yīng)該重新傳輸內(nèi)容。
通過(guò)配置 yii\filters\HttpCache::etagSeed 屬性向客戶(hù)端發(fā)送?ETag
?頭。該屬性的值應(yīng)該為 PHP callable 類(lèi)型,返回的是一段種子字符用來(lái)生成 ETag 哈希值。該 callable 的參數(shù)和返回值應(yīng)該如下:
function ($action, $params)
以下是使用?ETag
?頭的示例:
public function behaviors(){
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['view'],
'etagSeed' => function ($action, $params) {
$post = $this->findModel(\Yii::$app->request->get('id'));
return serialize([$post->title, $post->content]);
},
],
];
}
上述代碼表明 HTTP 緩存只在?view
?操作時(shí)啟用。它會(huì)基于用戶(hù)請(qǐng)求的標(biāo)題和內(nèi)容生成一個(gè)?ETag
?HTTP 頭。當(dāng)瀏覽器第一次訪(fǎng)問(wèn)?view
頁(yè)時(shí),服務(wù)器將會(huì)生成頁(yè)面并發(fā)送至客戶(hù)端瀏覽器。之后客戶(hù)端瀏覽器標(biāo)題和內(nèi)容沒(méi)被修改在期間訪(fǎng)問(wèn)該頁(yè),服務(wù)器將不會(huì)重新生成頁(yè)面,瀏覽器會(huì)使用之前客戶(hù)端緩存下來(lái)的內(nèi)容。因此服務(wù)端渲染和內(nèi)容傳輸都將省去。
ETag 相比?Last-Modified
?能實(shí)現(xiàn)更復(fù)雜和更精確的緩存策略。例如,當(dāng)站點(diǎn)切換到另一個(gè)主題時(shí)可以使 ETag 失效。
復(fù)雜的 Etag 生成種子可能會(huì)違背使用?HttpCache
?的初衷而引起不必要的性能開(kāi)銷(xiāo),因?yàn)轫憫?yīng)每一次請(qǐng)求都需要重新計(jì)算 Etag。請(qǐng)?jiān)囍页鲆粋€(gè)最簡(jiǎn)單的表達(dá)式去觸發(fā) Etag 失效。
注意:為了遵循?RFC 7232(HTTP 1.1 協(xié)議),如果同時(shí)配置了?
ETag
?和?Last-Modified
?頭,HttpCache
?將會(huì)同時(shí)發(fā)送它們。并且如果客戶(hù)端同時(shí)發(fā)送?If-None-Match
?頭和?If-Modified-Since
?頭,則只有前者會(huì)被接受。
Cache-Control
?頭Cache-Control
?頭指定了頁(yè)面的常規(guī)緩存策略??梢酝ㄟ^(guò)配置 yii\filters\HttpCache::cacheControlHeader 屬性發(fā)送相應(yīng)的頭信息。默認(rèn)發(fā)送以下頭:
Cache-Control: public, max-age=3600
當(dāng)頁(yè)面使 session 時(shí),PHP 將會(huì)按照 PHP.INI 中所設(shè)置的?session.cache_limiter
?值自動(dòng)發(fā)送一些緩存相關(guān)的 HTTP 頭。這些 HTTP 頭有可能會(huì)干擾你原本設(shè)置的?HttpCache
?或讓其失效。為了避免此問(wèn)題,默認(rèn)情況下?HttpCache
?禁止自動(dòng)發(fā)送這些頭。想改變這一行為,可以配置 yii\filters\HttpCache::sessionCacheLimiter 屬性。該屬性接受一個(gè)字符串值,包括?public
,private
,private_no_expire
,和?nocache
。請(qǐng)參考 PHP 手冊(cè)中的緩存限制器了解這些值的含義。