核心機制對照
| 標頭 | 類型 | 請求配對標頭 | 適用場景 | 優先級 |
| Last-Modified | 響應 | If-Modified-Since | 靜態檔案、動態頁面 (有修改時間) | 弱驗證器 |
| ETag | 響應 | If-None-Match | 靜態檔案、需強一致性驗證 | 強驗證器 |
| Expires | 響應 | - (無條件快取) | 極少變動資源 (圖片、CSS、JS) | HTTP/1.0 相容 |
| Cache-Control | 響應/請求 | - | 精細控制 (max-age, no-cache, must-revalidate) | HTTP/1.1 標準,優先於 Expires |
工作流程
- 首次請求 → 伺服器回 200 + 資源 +
Last-Modified/ETag/Expires/Cache-Control。
- 瀏覽器快取資源與標頭。
- 再次請求 → 瀏覽器送
If-Modified-Since + If-None-Match。
- 伺服器比對:
- 均未變更 → 304 Not Modified (空內文),瀏覽器用快取。
- 任一變更 → 200 OK + 新資源 + 新標頭。
Expires/Cache-Control: max-age 內 → **完全不發請求**,直接讀快取 (含 F5 強制重整除外)。
Apache 配置 (mod_expires + mod_headers)
ExpiresActive On
# 靜態資源 1 年
ExpiresDefault "access plus 1 year"
Header append Cache-Control "public"
# HTML 30 分鐘
ExpiresDefault "access plus 30 minutes"
Header append Cache-Control "public, must-revalidate"
# ETag 預設開啟 (FileETag MTime Size),可精簡為:
FileETag MTime Size
Nginx 配置
# 靜態資源長期快取
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|woff2?)$ {
expires 1y;
add_header Cache-Control "public";
# Nginx 預設不產生 ETag (作者觀點: Last-Modified 足夠)
# 需 ETag 可編譯第三方模組 nginx-static-etags
}
# HTML 短期快取
location ~* \.html?$ {
expires 30m;
add_header Cache-Control "public, must-revalidate";
}
動態頁面 (PHP) 手動輸出快取標頭
關鍵提醒
- 動態頁啟用快取時 **必須關閉 Session 自動啟動** (或手動
session_cache_limiter('public')),否則 Set-Cookie 會導致快取失效。
Cache-Control: must-revalidate 確保過期後必須回源驗證,避免臟讀。
- Squid/varnish 等邊緣快取需配合
refresh_pattern 忽略 Cache-Control: no-cache 的強制重整請求。