APP_DEBUG=false是自定义错误页面生效的前提,开发时显示Whoops页是设计行为;需将404.blade.php等文件置于resources/views/errors/下,命名严格为纯数字+.blade.php,且须清除配置与视图缓存。

APP_DEBUG=false 是自定义错误页面生效的前提
开发时看到的“Whoops”调试页不是 bug,是设计行为。只要 APP_DEBUG=true,无论 resources/views/errors/404.blade.php 是否存在,都不会被渲染——Laravel 会强制走调试堆栈页。生产环境必须关掉它,否则数据库密码、API 密钥可能直接暴露在 HTML 源码里。
验证方式很简单:改 .env 文件两行:
APP_ENV=productionAPP_DEBUG=false
然后清缓存:php artisan config:clear,再访问一个不存在的路由(比如 /nonexistent),才能看到你写的 404.blade.php。
resources/views/errors/ 下放文件就能自动匹配状态码
不用注册、不用配置、不写 PHP 逻辑——只要文件名对得上 HTTP 状态码,Laravel 就自动调用。支持的文件名包括:404.blade.php、500.blade.php、403.blade.php、419.blade.php(CSRF 过期)等。
注意三点:
- 视图里可直接用
{{ $exception->getMessage() }}获取异常信息,但仅限于APP_DEBUG=false且该异常最终落到renderHttpException()流程中(如NotFoundHttpException) - 文件必须放在
resources/views/errors/,不能嵌套子目录;也不能叫error-404.blade.php或404.php - 如果同时存在
404.blade.php和model-not-found.blade.php,前者优先;后者只在Handler::render()中显式调用时才生效
Handler.php 的 render() 方法决定返回什么响应
静态页面解决不了所有问题。比如你要对 ModelNotFoundException 返回 JSON,或对 InsufficientBalanceException 返回带错误码的 API 响应,就得动 app/Exceptions/Handler.php 的 render() 方法。
常见写法示例:
use Illuminate\Database\Eloquent\ModelNotFoundException;
use App\Exceptions\InsufficientBalanceException;
public function render($request, Throwable $exception)
{
if ($exception instanceof ModelNotFoundException) {
return response()->view('errors.404', [], 404);
}
if ($exception instanceof InsufficientBalanceException) {
return response()->json([
'code' => 'balance_insufficient',
'message' => $exception->getMessage()
], 400);
}
return parent::render($request, $exception);
}
关键点:
- 一定要用
instanceof判断类型,别用get_class()或字符串匹配——容易漏掉继承链 - 调用
parent::render()是兜底行为,删掉它会导致其他异常全部 500 - 不要在
render()里做耗时操作(如 DB 查询、HTTP 请求),它运行在响应生成阶段,会影响首字节时间
report() 方法控制日志记录与告警分发
report() 不影响用户看到什么,只管“要不要记、往哪记、要不要告警”。默认会把所有未被 $dontReport 过滤的异常写进 storage/logs/laravel.log。
实用配置建议:
- 把高频但无意义的异常加入
$dontReport数组,比如NotFoundHttpException、MethodNotAllowedHttpException,避免日志刷屏 - 想限制日志级别?在
config/app.php加'log_level' => 'error',这样debug、info级别就不再写入 - 要对接 Sentry?在
report()里加Sentry::captureException($exception),但记得先判断环境:if (app()->environment('production')) { ... }
真正容易被忽略的是:日志文件滚动策略。用 'log' => 'daily' 时,默认只保留 5 天日志。如果线上出问题需要回溯,很可能发现 laravel-2026-06-20.log 已被删——得提前设 'log_max_files' => 30。


















