Laravel 5.1 中,致命錯誤 (FatalErrorException) 會繞過常規例外處理,直接顯示預設錯誤頁。需在 App\Exceptions\Handler 中攔截並回應自定義視圖。
app/Exceptions/Handler.phpnamespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\Debug\Exception\FatalErrorException;
class Handler extends ExceptionHandler {
public function render($request, Exception $e) {
// ModelNotFound 轉 404
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
$e = new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException($e->getMessage(), $e);
}
// 關鍵:攔截生產環境致命錯誤,回應自定義視圖
if ($e instanceof FatalErrorException && !config('app.debug')) {
return response()->view('errors.default', [], 500);
}
return parent::render($request, $e);
}
}
resources/views/errors/default.blade.php<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>系統錯誤 - 500</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
display: flex; align-items: center; justify-content: center; min-height: 100vh;
margin: 0; background: #f5f5f5; }
.card { background: white; padding: 3rem; border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; max-width: 400px; }
h1 { color: #e74c3c; margin-bottom: 1rem; }
p { color: #666; line-height: 1.6; }
a { color: #3498db; text-decoration: none; }
a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="card">
<h1>😕 系統發生錯誤</h1>
<p>我們已記錄此錯誤,技術團隊正在緊急處理中。</p>
<p>請稍後重試,或 返回首頁。</p>
</div>
</body>
</html>
public function render($request, Exception $e) {
if (!config('app.debug')) {
// 500 伺服器錯誤
if ($e instanceof FatalErrorException || $e instanceof \ErrorException) {
return response()->view('errors.500', [], 500);
}
// 404 找不到
if ($e instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
return response()->view('errors.404', [], 404);
}
// 403 無權限
if ($e instanceof \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException) {
return response()->view('errors.403', [], 403);
}
// 419 CSRF 失效
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
return response()->view('errors.419', [], 419);
}
}
return parent::render($request, $e);
}
resources/views/
└── errors/
├── 404.blade.php
├── 500.blade.php
├── 403.blade.php
├── 419.blade.php
└── default.blade.php (fallback)
Laravel 5.5+ 會自動根據 HTTP 狀態碼尋找對應視圖,無需手動 render() 判斷。
APP_DEBUG=false,否則仍顯示詳細錯誤頁Log::error() 或整合 Sentry 等錯誤追蹤服務# 臨時在路由觸發 500 測試
Route::get('test-500', function() {
throw new \ErrorException('Test fatal error');
});
訪問 /test-500 應顯示自定義錯誤頁,而非預設堆疊追蹤。
三分鐘配置,讓生產環境錯誤頁從「工程師專用」變為「用戶友善」。