使用 Apache 的 .htaccess 設定自訂 404 錯誤頁面,是提升使用者體驗、保持品牌一致性的基本功。本文涵蓋基本設定、常見陷阱、進階技巧與除錯步驟。
在網站根目錄建立/編輯 .htaccess:
# 設定 404 錯誤頁面(相對於 DocumentRoot)
ErrorDocument 404 /404.html
# 或使用 PHP 動態頁面
ErrorDocument 404 /404.php
404.html 範例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>頁面不存在 - 我的網站</title>
</head>
<body>
<h1>404 - 找不到頁面</h1>
<p>抱歉,您請求的頁面不存在或已移動。</p>
<a href="/"><- 返回首頁</a>
</body>
</html>
httpd.conf / apache2.conf 中對應目錄設定:
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All # 關鍵:允許 .htaccess 覆蓋 ErrorDocument 等指令
Require all granted
</Directory>
AllowOverride All:允許所有指令覆蓋。AllowOverride FileInfo:僅允許檔案資訊類指令(包含 ErrorDocument),較安全。systemctl reload apache2 或 apachectl graceful。| 問題 | 原因 | 解決 |
|---|---|---|
| 設定後無效果,仍顯示 Apache 預設 404 | AllowOverride None 或未重啟 Apache | 檢查主設定檔 AllowOverride,重啟 Apache |
| 404 頁面本身也回傳 200 OK | ErrorDocument 頁面正常回應,未保留 404 狀態碼 | PHP 中加入 http_response_code(404); |
| 使用絕對 URL 導致雙重請求 | ErrorDocument 404 https://example.com/404.html | 必須使用相對路徑 /404.html |
| 子目錄 .htaccess 不生效 | 父目錄 AllowOverride 限制、或路徑寫錯 | 路徑永遠相對 DocumentRoot,非相對 .htaccess 位置 |
| 子目錄想用不同 404 頁面 | 在子目錄 .htaccess 覆蓋設定 | 子目錄 .htaccess 加入 ErrorDocument 404 /sub/404.html |
<?php
// 404.php
http_response_code(404); // 關鍵:確保回傳 404 狀態碼
$requestUri = $_SERVER['REQUEST_URI'];
$referer = $_SERVER['HTTP_REFERER'] ?? '直接存取';
// 記錄 404 日誌(資料庫/檔案/系統日誌)
error_log("404: $requestUri | Referer: $referer | IP: {$_SERVER['REMOTE_ADDR']}");
// 簡易建議:嘗試匹配相似網址
$suggestions = [];
// 實作邏輯:資料庫 LIKE 查詢、Levenshtein 距離等
// 輸出 HTML
?>
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>頁面不存在</title></head>
<body>
<h1>404 - 找不到頁面</h1>
<p>請求網址:<code><?= htmlspecialchars($requestUri) ?></code></p>
<?php if ($suggestions): ?>
<p>您可能想找:</p>
<ul>
<?php foreach ($suggestions as $url => $title): ?>
<li><a href="<?= $url ?>"><?= htmlspecialchars($title) ?></a></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<a href="/">返回首頁</a>
</body></html>
# .htaccess
ErrorDocument 404 /404-handler.php
# 404-handler.php
<?php
http_response_code(404);
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'en', 0, 2);
$lang = in_array($lang, ['en', 'zh', 'ja']) ? $lang : 'en';
include "404.$lang.php";
?>
# .htaccess for SPA
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
# 真正的 404 由前端路由處理,或在 index.html 內判斷
# 此設定下 Apache 不會觸發 ErrorDocument 404
AllowOverride FileInfo 或 All 已設定並重啟 Apache?/ 開頭)?/var/log/apache2/error.log 無相關錯誤?ErrorDocument 400 /errors/400.html
ErrorDocument 401 /errors/401.html
ErrorDocument 403 /errors/403.html
ErrorDocument 500 /errors/500.html
ErrorDocument 502 /errors/502.html
ErrorDocument 503 /errors/503.html
善用自訂錯誤頁面,不僅能提供友善體驗,還能透過日誌分析發現死連結、攻擊嘗試、爬蟲異常等問題,是網站維運的重要一環。