自定义PHP框架中实现自定义404错误页面的求助
我最近在自己搭建的PHP MVC框架里开发项目,结果发现当访问不存在的路由时(比如plan/plan/views),框架直接抛出了一个未捕获的异常,页面上显示的是这样的致命错误信息:
Fatal error Uncaught exception: 'Exception' Message: 'No route matched.' Stack trace: #0 C:\xampp\htdocs\projects\wash\public\index.php(40): Core\Router->dispatch('plan/plan/views') #1 {main} Thrown in 'C:\xampp\htdocs\projects\wash\Core\Router.php' on line 130
这个信息在开发阶段排查问题还挺有用,但要是上线后给用户看到就太不友好了,我想改成显示自己设计的404页面,有没有懂行的大佬能给我指指路呀?
别担心,这个问题其实不难解决,咱们只需要在框架里把这个异常捕获并处理掉就行,具体步骤我给你整理好了:
- 第一步:在入口文件捕获路由异常
找到项目的入口文件public/index.php,就是调用Router->dispatch()的那个地方,把这段代码用try-catch块包起来。这样当路由匹配失败抛出异常时,咱们就能接管处理逻辑,不让系统直接输出错误堆栈。
修改后的index.php代码大概是这样的:
try { // 假设你是这样获取请求路由并分发的 $requestedRoute = $_SERVER['REQUEST_URI']; $router = new Core\Router(); $router->dispatch($requestedRoute); } catch (Exception $e) { // 先判断是不是路由未匹配的异常 if ($e->getMessage() === 'No route matched.') { // 先发送404的HTTP状态码,这很重要,搜索引擎能识别 http_response_code(404); // 加载你自己写的404视图文件 require_once '../views/errors/404.php'; } else { // 如果是其他异常,比如服务器错误,就处理成500页面 http_response_code(500); require_once '../views/errors/500.php'; // 开发环境下可以临时输出异常详情方便调试,上线记得注释掉 // echo "错误信息:" . $e->getMessage() . "<br>"; // echo "错误文件:" . $e->getFile() . " 第" . $e->getLine() . "行"; } }
- 第二步:制作自定义404视图页面
在你的视图目录下新建一个errors文件夹,里面创建404.php,写一个友好的页面就行,比如:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>404 - 页面走丢啦</title> <style> .error-page { text-align: center; margin: 100px auto; max-width: 600px; font-family: '微软雅黑', sans-serif; } .error-code { font-size: 6rem; color: #ff4444; margin: 0; } .error-message { font-size: 1.5rem; color: #666; margin: 20px 0; } .back-home { display: inline-block; padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; margin-top: 30px; } .back-home:hover { background: #0056b3; } </style> </head> <body> <div class="error-page"> <h1 class="error-code">404</h1> <p class="error-message">哎呀,您访问的页面不存在或者已经搬家啦😥</p> <a href="/" class="back-home">返回首页</a> </div> </body> </html>
- 第三步:优化异常判断(可选但推荐)
如果想让代码更严谨,咱们可以自定义一个异常类,专门用来表示路由未找到的情况,这样就不用依赖错误信息的字符串来判断了。
比如在Core目录下创建Exceptions/RouteNotFoundException.php:
namespace Core\Exceptions; class RouteNotFoundException extends \Exception { public function __construct($message = 'No route matched.', $code = 404, \Throwable $previous = null) { parent::__construct($message, $code, $previous); } }
然后去Core/Router.php里找到抛出异常的地方,把原来的Exception改成咱们自定义的异常:
// 原来的代码 // throw new \Exception('No route matched.'); // 改成 throw new \Core\Exceptions\RouteNotFoundException();
这样在index.php的try-catch里就可以直接捕获这个特定的异常:
// 先捕获路由未找到的异常 catch (\Core\Exceptions\RouteNotFoundException $e) { http_response_code(404); require_once '../views/errors/404.php'; } catch (Exception $e) { // 处理其他所有异常 http_response_code(500); require_once '../views/errors/500.php'; }
这样弄完之后,再访问不存在的路由,就能看到你自己设计的友好404页面啦,既专业又能提升用户体验~
内容来源于stack exchange

