透過 header() 送出正確的 HTTP 快取標頭,可大幅降低伺服器負載、加快頁面載入。本文說明「禁用快取」與「啟用快取」兩大場景的標頭設定,並補充 Apache mod_expires 靜態檔案快取設定。
header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // 過去日期
header("Pragma: no-cache"); // HTTP/1.0 相容
注意: header() 前不可有任何輸出(含空白、BOM)。
$seconds = 3600;
$ts = gmdate("D, d M Y H:i:s", time() + $seconds) . " GMT";
header("Expires: $ts");
header("Pragma: cache");
header("Cache-Control: max-age=$seconds");
關鍵: 使用 gmdate 而非 date 產生 GMT 時間,避免時區誤差。
header("Cache-Control: public");
header("Pragma: cache");
$offset = 30 * 24 * 3600;
$expStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
header($expStr);
針對內容變動不頻繁的動態頁,可產生 ETag:
$content = getContent(); // 取得輸出內容
$etag = md5($content);
header("ETag: $etag");
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) {
header("HTTP/1.1 304 Not Modified");
exit;
}
echo $content;
在 .htaccess 加入:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType text/html "access plus 10 minutes"
</IfModule>
若模組未安裝,規則會被忽略不報錯。建議搭配 Gzip 壓縮(mod_deflate)使用。
header("Cache-Control: max-age=...") 與 Expires 時間必須一致,否則瀏覽器行為不可預期。session_start() 會自動送出 Cache-Control: no-store,若需快取 Session 頁面,需在 session_start 後覆寫標頭。