| Header | HTTP 版本 | 作用 |
|---|---|---|
| Last-Modified | 1.0 | 資源最後修改時間(GMT) |
| ETag | 1.1 | 資源實體標籤(哈希/版本號),強驗證器 |
| Expires | 1.0 | 絕對過期時間(GMT),受客戶端時鐘影響 |
| Cache-Control | 1.1 | 相對過期、驗證策略、存儲指令(優先級最高) |
// 禁止緩存(動態頁、隱私數據)
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Pragma: no-cache // HTTP/1.0 兼容
Expires: -1
// 公開緩存 1 年(靜態資源帶版本號)
Cache-Control: public, max-age=31536000, immutable
// 私有緩存 10 分鐘,需回源驗證
Cache-Control: private, max-age=600, must-revalidate
// 代理緩存 1 天,客戶端 1 小時
Cache-Control: s-maxage=86400, max-age=3600
<?php
// 1. 獲取數據最後修改時間(如文章 updated_at)
$lastMod = $article->updated_at; // DateTime 對象或時間戳
$etag = md5($article->id . $lastMod->getTimestamp() . $article->content);
// 2. 發送驗證頭
header('Last-Modified: ' . $lastMod->format('D, d M Y H:i:s') . ' GMT');
header('ETag: "' . $etag . '"');
// 3. 檢查客戶端條件請求
$ifMod = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false;
$ifMatch = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : false;
if (($ifMod && $ifMod >= $lastMod->getTimestamp()) || ($ifMatch && $ifMatch === $etag)) {
header('HTTP/1.1 304 Not Modified');
exit; // 節省帶寬與渲染
}
// 4. 正常輸出內容
header('Cache-Control: private, max-age=60, must-revalidate');
// ... 輸出 HTML
# Nginx
location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
etag on;
}
原則:文件名含哈希/版本號(如 app.abc123.js) → 可安全設置長期緩存 + immutable;更新文件即改名,自動失效舊緩存。