首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

ThinkPHP 3.2 自定義 404 錯誤頁面的完整配置指南

     編輯:PHP 相關知識

ThinkPHP 3.2 自定義 404 錯誤頁面的完整配置指南

ThinkPHP 3.2 透過「空模組」與「空操作」機制,提供了優雅的 404 頁面處理方案。本文詳細說明如何建立 EmptyAction、配置 CommonAction 空操作、製作 404 模板、以及 Nginx/Apache 層面的配合配置。

一、核心原理:空模組與空操作

  • 訪問不存在的模組(如 /NotExistModule/Index) → 觸發 EmptyAction
  • 訪問存在模組但不存在的操作(如 /Index/NotExistAction) → 觸發該模組的 _empty() 方法
  • 結合兩者,可攔截所有無效路由並統一導向 404 頁面

二、建立空模組控制器

<?php
// Application/Lib/Action/EmptyAction.class.php
class EmptyAction extends CommonAction {
    /**
     * 空模組入口:訪問不存在的模組時觸發
     */
    public function _empty() {
        // 發送標準 404 狀態碼(關鍵:利於 SEO 與監控)
        header('HTTP/1.0 404 Not Found');
        header('Status: 404 Not Found');
        
        // 禁用佈局(如有)
        $this->layout(false);
        
        // 顯示 404 模板
        $this->display('Public:404');
    }
}

三、在基礎控制器定義空操作

<?php
// Application/Lib/Action/CommonAction.class.php
class CommonAction extends Action {
    // ... 其他共用邏輯 ...
    
    /**
     * 空操作入口:訪問不存在的 Action 時觸發
     * 透過 R() 重定向到空模組的 _empty 方法,統一處理邏輯
     */
    public function _empty() {
        // 方法一:內部重定向(推薦,保持 URL 不變)
        R('Empty/_empty');
        
        // 方法二:直接輸出(若不需複用邏輯)
        // header('HTTP/1.0 404 Not Found');
        // $this->display('Public:404');
    }
}

四、製作 404 模板檔案

<!-- Application/Tpl/Public/404.html -->
<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <title>頁面不存在 - {$site_name|default='本站'}</title>
    <meta name="robots" content="noindex, nofollow">
    <style>
        body { font-family: 'Microsoft JhengHei', sans-serif; background: #f8f9fa; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; }
        .container { text-align: center; padding: 40px; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,.1); max-width: 400px; }
        h1 { font-size: 96px; color: #dc3545; margin: 0 0 16px; line-height: 1; }
        p { color: #6c757d; font-size: 18px; margin-bottom: 24px; }
        a { display: inline-block; padding: 12px 28px; background: #007bff; color: white; border-radius: 4px; text-decoration: none; font-weight: 500; }
        a:hover { background: #0056b3; }
        .links { margin-top: 20px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
    </style>
</head>
<body>
    <div class="container">
        <h1>404</h1>
        <p>您訪問的頁面不存在或已被移除</p>
        <a href="__ROOT__/">返回首頁</a>
        <div class="links">
            <a href="__ROOT__/sitemap">網站地圖</a>
            <a href="__ROOT__/contact">聯繫我們</a>
            <a href="javascript:history.back()">返回上一頁</a>
        </div>
    </div>
    <script>
        // 可選:記錄 404 URL 供分析
        fetch('/api/log-404', { method: 'POST', body: JSON.stringify({ url: location.href, referrer: document.referrer }) }).catch(()=>{});
    </script>
</body>
</html>

五、處理靜態資源 404(避免進入 PHP)

圖片、CSS、JS 等靜態檔案不存在時,不應進入 ThinkPHP 處理,由 Web Server 直接返回 404,節省資源:

Nginx 配置

server {
    root /var/www/html;
    index index.php index.html;
    
    location / {
        # 靜態檔案直接嘗試服務,不存在則 404(不進入 PHP)
        try_files $uri $uri/ @thinkphp;
    }
    
    location @thinkphp {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root/index.php;
        include fastcgi_params;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    
    # 明確排除靜態資源
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt|woff2?)$ {
        expires 30d;
        access_log off;
        try_files $uri =404; # 關鍵:不存在直接 404
    }
}

Apache (.htaccess)

<IfModule mod_rewrite.c>
    RewriteEngine On
    # 靜態檔案直接服務
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]
    # 其他轉發到 index.php
    RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>

# 靜態資源不存在直接 404
<FilesMatch "\.(jpg|jpeg|png|gif|ico|css|js|pdf|txt|woff2?)$">
    ErrorDocument 404 "Not Found"
</FilesMatch>

六、進階:記錄 404 日誌供分析

<?php
// Application/Lib/Action/EmptyAction.class.php (補充)
public function _empty() {
    header('HTTP/1.0 404 Not Found');
    
    // 記錄 404 訪問(非同步寫入,不阻塞響應)
    $logData = [
        'url' => $_SERVER['REQUEST_URI'],
        'referrer' => $_SERVER['HTTP_REFERER'] ?? '',
        'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '',
        'ip' => $this->getClientIp(),
        'time' => date('Y-m-d H:i:s'),
    ];
    // 寫入檔案或推送到 Redis 佇列
    $logFile = RUNTIME_PATH . 'Logs/404_' . date('Ymd') . '.log';
    @file_put_contents($logFile, json_encode($logData, JSON_UNESCAPED_UNICODE) . "\n", FILE_APPEND);
    
    $this->display('Public:404');
}

private function getClientIp() {
    foreach (['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR'] as $key) {
        if (!empty($_SERVER[$key])) return $_SERVER[$key];
    }
    return 'unknown';
}

七、ThinkPHP 5.x/6.x 的差異說明

ThinkPHP 5.0+ 採用異常處理機制,配置更簡單:

<?php
// config/app.php (TP 5.x/6.x)
return [
    // ...
    'exception_tmpl' => APP_PATH . 'view/public/404.html', // 全域異常模板
    'exception_handle' => '\\app\\common\\exception\\HttpException', // 自定義異常處理類
];

// app/common/exception/HttpException.php
namespace app\common\exception;
use think\exception\Handle;
use think\Response;

class HttpException extends Handle {
    public function render(\Exception $e): Response {
        if ($e instanceof \think\exception\HttpException && $e->getCode() == 404) {
            return Response::create(view('public/404'), 'html', 404);
        }
        return parent::render($e);
    }
}

八、測試清單

  • [ ] 訪問 /NonExistModule → 顯示 404 頁面、狀態碼 404
  • [ ] 訪問 /Index/NonExistAction → 顯示 404 頁面、狀態碼 404
  • [ ] 訪問存在控制器但不存在方法 → 顯示 404
  • [ ] 訪問不存在的靜態檔 /static/missing.css → Nginx 直接 404、不進 PHP
  • [ ] 搜尋引擎模擬工具檢查 HTTP/1.0 404 Not Found 正確返回
  • [ ] 404 頁面包含「返回首頁」「網站地圖」等導航連結

正確配置 404 頁面不僅能提升用戶體驗,更能避免搜尋引擎索引無效頁面,是專案上線前的必檢項目。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved