自定义错误页面不生效主因是app_debug=true未关闭;需同时满足app_debug=false、异常映射为明确http状态码、web服务器未拦截,且blade文件命名严格为数字+.blade.php。

自定义错误页面不会生效,90% 是因为 APP_DEBUG=true 没关,而不是 Blade 文件写错了。
为什么 404/500 页面死活不显示
开发环境下 Laravel 强制走 Whoops 调试页,APP_DEBUG=true 时 resources/views/errors/404.blade.php 和 500.blade.php 完全被忽略。必须同时满足以下三点才可能看到自定义页:
-
APP_DEBUG=false(.env 中设置) - 异常最终被映射为明确 HTTP 状态码(如
NotFoundHttpException→ 404,ServerErrorHttpException→ 500) - Web 服务器没拦截——检查 Nginx 是否配了
error_page 404 /404.html,有就删掉
文件命名必须严格:只能是纯数字 + .blade.php,比如 404.blade.php 合法,not-found.blade.php、404.php、404.blade 全部无效。
怎么让 ModelNotFoundException 显示 404 页面
默认它会报 500,因为 ModelNotFoundException 不是 HTTP 异常,Laravel 不自动映射状态码。得在 App\Exceptions\Handler::render() 里手动处理:
<pre class="brush:php;toolbar:false;">use Illuminate\Database\Eloquent\ModelNotFoundException;
public function render($request, Throwable $exception)
{
if ($exception instanceof ModelNotFoundException) {
return response()->view('errors.404', [], 404);
}
return parent::render($request, $exception);
}
注意:response()->view()
$exception 进去——404 视图里拿不到 $exception 变量,只有 500 页面才支持。
别在 render() 里做数据库查询或调用服务,异常发生时环境可能已损坏;也别 throw 新异常,会触发无限递归。
API 请求出错时别返回 HTML 页面
前端调 /api/orders 出错,你返回一个 404.blade.php 页面,前端拿到的是 HTML 字符串,解析失败。得判断请求类型:
<pre class="brush:php;toolbar:false;">if ($exception instanceof ModelNotFoundException && $request->expectsJson()) {
return response()->json(['message' => 'Resource not found'], 404);
}
if ($exception instanceof ModelNotFoundException) {
return response()->view('errors.404', [], 404);
}
$request->expectsJson()
response()->json() 的状态码必须和语义一致,比如 TokenMismatchException 应该返回 419,不是 403 或 500。
自定义异常类怎么接入 render 流程
运行 php artisan make:exception PaymentFailedException 创建后,它默认继承 Exception,不会被自动识别为 HTTP 异常。要在 render() 里显式拦截:
<pre class="brush:php;toolbar:false;">use App\Exceptions\PaymentFailedException;
if ($exception instanceof PaymentFailedException) {
return response()->view('errors.payment-failed', [
'message' => $exception->getMessage()
], 402); // HTTP 402 Payment Required
}
别忘了清缓存:php artisan config:clear
php artisan view:clear,否则改完 Handler.php 或 Blade 文件都看不到效果。OPCache 也可能导致类加载旧版本,必要时重启 PHP-FPM。
真正麻烦的不是写代码,而是异常从抛出到渲染之间穿过了路由、中间件、HTTP 内核多层,任何一层提前 abort 或 throw 都会让控制流跳过 Handler::render()。先确认异常真的到达了这里,再谈定制。











