隨著訪問量增長,動態頁面頻繁查詢數據庫、執行模板渲染會造成伺服器負載飆升。生成靜態 HTML 文件(頁面靜態化)是經典且高效的優化手段:首次訪問生成靜態文件,後續請求直接由 Web 伺服器(Nginx/Apache)靜態文件服務,繞過 PHP 解析與資料庫查詢。本文實現一個通用的靜態緩存生成方法。
<?php
class HtmlCache {
/**
* 生成或更新靜態緩存文件
* @param string $root 靜態文件存放根目錄(需可寫權限)
* @param string $rule 文件命名規則(如 'article_123'),不含副檔名
* @param string $url 動態頁面完整 URL(將獲取其輸出內容)
* @return bool|int 成功返回寫入字節數,失敗返回 false
*/
public function setHtmlCache(string $root, string $rule, string $url) {
// 確保目錄存在
if (!is_dir($root)) {
mkdir($root, 0755, true);
}
$filepath = $root . $rule . '.html';
// 獲取動態頁面內容(觸發完整 MVC 流程)
$content = @file_get_contents($url);
if ($content === false) {
error_log("靜態化失敗:無法獲取 $url");
return false;
}
// 原子寫入:先寫臨時文件再重命名,防止讀取到半寫文件
$tmpfile = $filepath . '.tmp.' . mt_rand();
$bytes = @file_put_contents($tmpfile, $content);
if ($bytes === false) {
error_log("靜態化失敗:寫入文件失敗 $filepath");
return false;
}
@rename($tmpfile, $filepath); // 原子替換
return $bytes;
}
/**
* 刪除緩存(數據更新時調用)
*/
public function clearCache(string $root, string $rule): bool {
$filepath = $root . $rule . '.html';
return file_exists($filepath) ? unlink($filepath) : true;
}
}
| 場景 | 觸發緩存更新 |
|---|---|
| 文章發布/編輯 | 後台保存成功後呼叫 setHtmlCache() 重新生成 |
| 評論新增/審核 | 評論操作完成後重新生成對應文章頁 |
| 定時任務 | 每日凌晨重新生成首頁、列表頁等高頻頁面 |
| 手動清理 | 後台提供「更新緩存」按鈕呼叫 clearCache() |
# Nginx 站點配置片段
location / {
# 嘗試直接服務靜態文件
try_files /cache/$uri.html /cache/$uri/index.html @php;
}
location @php {
fastcgi_pass php-fpm;
# ... 其餘 PHP 處理配置
}
此配置下,請求 /article/123 會優先尋找 /cache/article/123.html,存在則直接返回,不經 PHP-FPM。
article_123_v2.html),更新時生成新文件、刪除舊文件,避免鎖定。ob_start() 捕獲頁面片段(如側邊欄、推薦列表)緩存,動態頁面組裝時 include 靜態片段。flock() 或 Redis 分布式鎖防止重複生成。靜態化不適合:強個性化頁面(用戶中心、購物車)、實時性極高數據(股票行情、即時聊天)、頻繁變動的列表頁。可採用「局部動態 + 整體靜態」混合模式(如 ESI、AJAX 回填)。