Yii 提供多層次快取方案,從資料快取、查詢快取到片段快取、頁面快取與 HTTP 快取,形成完整的效能優化體系。本文聚焦於伺服器端的頁面快取與客戶端的 HTTP 快取,這兩種機制雖同樣以減少重複運算為目標,但運作層面與適用場景截然不同。
透過 yii\filters\PageCache 過濾器實現,配置範例:
public function behaviors()
{
return [
[
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 60,
'variations' => [\Yii::$app->language],
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
],
];
}
兩者支援相同配置選項,核心差異在於實現方式:頁面快取基於過濾器,片段快取基於 Widget。兩者可同時使用,並可搭配動態內容功能。
利用瀏覽器快取機制減少伺服器渲染與傳輸開銷,僅對 GET/HEAD 請求生效。透過 yii\filters\HttpCache 設定三種 HTTP 標頭:
基於時間戳記判斷內容是否更新:
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');
},
],
];
}
運作流程:首次請求回傳內容與 Last-Modified 標頭;後續請求瀏覽器發送 If-Modified-Since,伺服器比對時間戳,未修改則回傳 304 Not Modified,瀏覽器直接使用快取。
基於內容哈希值實現更精確的快取驗證:
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]);
},
],
];
}
優勢:支援主題切換等非時間型變更導致的快取失效。注意:複雜的 ETag 種子生成可能抵消快取效益,建議尋找最簡表達式觸發失效。
指定通用快取策略,預設發送:
Cache-Control: public, max-age=3600
可透過 cacheControlHeader 屬性自訂。
PHP 預設會根據 session.cache_limiter 發送快取標頭,可能干擾 HttpCache。預設禁止自動發送,可透過 sessionCacheLimiter 屬性調整(值:public、private、private_no_expire、nocache)。
renderDynamic() 排除在片段快取之外public function behaviors()
{
return [
// HTTP 快取最外層
[
'class' => 'yii\filters\HttpCache',
'only' => ['index'],
'lastModified' => function ($action, $params) {
return Post::find()->max('updated_at');
},
],
// 頁面快取內層
[
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 300,
'variations' => [\Yii::$app->language],
],
];
}
這種分層快取架構能最大化效能效益:HTTP 快取攔截重複請求,頁面快取減少伺服器渲染運算,資料快取加速資料庫查詢。