在 ThinkPHP 專案中,優雅地處理不存在的模塊/控制器請求,返回標準 HTTP 404 狀態碼並展示自定義錯誤頁面,是提升用戶體驗與 SEO 友好度的關鍵。本文提供基於 EmptyAction 機制的標準實現方案,並涵蓋 Apache、Nginx、IIS 等主流 Web 服務器的配置細節。
在模塊目錄下建立 EmptyAction.class.php,繼承 Action 類並實現 _empty() 魔術方法:
<?php
class EmptyAction extends Action {
public function _empty() {
// 發送標準 HTTP 404 狀態碼
header("HTTP/1.0 404 Not Found");
// 渲染公共 404 模板(需預先建立 Tpl/Public/404.html)
$this->display("Public:404");
}
}
?>
原理:當 URL 請求的模塊不存在時,ThinkPHP 會自動尋找該模塊下的 EmptyAction,並調用 _empty() 方法處理,此時可統一輸出 404 頁面。
框架層面僅能處理「模塊存在但操作不存在」或「進入 EmptyAction」的情況。若請求的模塊目錄本身不存在,Web 服務器會直接返回預設 404,繞過 PHP 執行。因此需在服務器層配置自定義錯誤頁面指向框架入口,確保所有 404 統一由框架處理。
ErrorDocument 404 /index.php
將 404 錯誤重定向至框架入口文件,由 ThinkPHP 路由解析並觸發 EmptyAction。
server {
# ...
error_page 404 /index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
<configuration>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" path="/index.php" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
</configuration>
或在傳統 ASP.NET 模式下:
<configuration>
<system.web>
<customErrors mode="On" defaultRedirect="/error.html">
<error statusCode="404" redirect="/index.php" />
</customErrors>
</system.web>
</configuration>
在 Tpl/Public/404.html 中必須包含狀態碼輸出,防止搜尋引擎誤判為軟 404:
<?php header("HTTP/1.0 404 Not Found"); ?>
<!DOCTYPE html>
<html>
<head><title>頁面不存在</title></head>
<body>
<h1>404 - 頁面未找到</h1>
<p>您訪問的頁面不存在或已被移除。</p>
<a href="/>返回首頁</a>
</body>
</html>
在具體 Action 中根據業務數據決定是否拋出 404:
public function detail($id) {
$article = M('Article')->find($id);
if (empty($article)) {
header("HTTP/1.1 404 Not Found");
header("Status: 404 Not Found");
$this->display("Public:404");
exit;
}
$this->assign('article', $article);
$this->display();
}
EmptyAction 中 header() 是否在輸出內容前調用,且未被緩衝區吞沒。ErrorDocument 指向的路徑不會再次觸發 404(如指向靜態 HTML 而非框架入口)。existingResponse="Replace"。結合 EmptyAction 機制與 Web 服務器錯誤頁面配置,可實現 ThinkPHP 專案全鏈路的標準化 404 處理:框架負責業務邏輯 404,服務器負責靜態資源/路由不存在 404,雙重保障提升專案專業度與 SEO 表現。