新版 Laravel 异常处理: 配置异常报告和渲染逻辑
在新版的 Laravel 中,异常处理完全集中在项目的 bootstrap/app.php 文件中。从 Laravel 11 开始,就没有 app/Exceptions/Handler.php 这个文件了。
Laravel 11 对其应用骨架进行了大规模的“瘦身”,将原本分散在各个文件中的配置进行了集中管理:
去掉了
app/Exceptions/Handler.php,异常处理完全移到了bootstrap/app.php的withExceptions()方法中。去掉了
app/Http/Kernel.php,中间件的配置也完全移到了bootstrap/app.php的withMiddleware()方法中。精简了
config/目录,默认只保留了最核心的几个配置文件(其他配置采用框架底层默认值,需要时可以通过命令发布出来)。
所以,现在如果你使用的是 Laravel 11、Laravel 12 或 Laravel 13,所有全局的异常捕获、重定向、API 错误返回格式,都需要直接在 bootstrap/app.php 里面写闭包来配置。
1. 核心入口点
打开 bootstrap/app.php,你会看到类似下面的结构。我们需要在 withExceptions 闭包中编写逻辑:
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) { // 中间件配置...
})
->withExceptions(function (Exceptions $exceptions) { // ─── 所有的异常处理逻辑写在这里 ───
})
->create();2. 常用配置场景与代码示例
你可以根据需求,在 withExceptions 闭包中链式调用或直接调用以下方法:
自定义渲染(修改 HTTP 响应)
当某个特定的异常发生时,如果你想让用户看到自定义的视图或返回特定的 JSON 数据,可以使用 render 方法:
use App\Exceptions\InvalidOrderException;
use Illuminate\Http\Request;
$exceptions->render(function (InvalidOrderException $e, Request $request) {
// 如果客户端请求的是 JSON 格式(比如 API 请求)
if ($request->expectsJson()) {
return response()->json(['error' => '订单处理失败'], 422);
}
// 否则返回自定义的错误页面视图
return response()->view('errors.invalid-order', ['message' => $e->getMessage()], 500);
});自定义报告(发送错误到外部系统)
默认情况下,Laravel 会将异常记录到本地日志。如果你需要在发生特定错误时,将它们发送到第三方监控(如 Sentry、Logtail)或触发告警:
use App\Exceptions\PaymentFailedException;
$exceptions->report(function (PaymentFailedException $e) {
// 调用第三方 SDK 或发送通知邮件
// Sentry::captureException($e);
});忽略特定异常(不记录日志)
如果你想让某些无关紧要的异常保持沉默,不污染本地的日志文件:
use App\Exceptions\TemporaryNetworkHiccupException;
// 方式 A:直接忽略指定的异常类
$exceptions->dontReport([
TemporaryNetworkHiccupException::class,
]);
// 方式 B:根据动态条件来决定是否忽略
$exceptions->dontReportWhen(function (Throwable $e) {
return $e instanceof TemporaryNetworkHiccupException && $e->getCode() === 200;
});强制让特定路由返回 JSON
有时不管客户端是否带有 Accept: application/json 请求头,你都希望 API 路由在出错时能够强制返回 JSON 响应:
use Illuminate\Http\Request;
use Throwable;
$exceptions->shouldRenderJsonWhen(function (Request $request, Throwable $e) {
// 如果请求路径以 api/ 或 admin/api/ 开头,强制返回 JSON 错误
if ($request->is('api/*') || $request->is('admin/api/*')) {
return true;
}
return $request->expectsJson();
});修改特定异常的日志级别
有些第三方包抛出的异常可能会被 Laravel 默认记录为 ERROR 或 CRITICAL。如果你觉得它没那么严重,可以降低它的日志等级:
use PDOException; use Psr\Log\LogLevel; // 将数据库连接异常的日志级别提升为最高级的 CRITICAL $exceptions->level(PDOException::class, LogLevel::CRITICAL);
3. 完整配置示例
在实际项目中,你可以将这些配置组合在一起,写成一个清晰、干净的闭包:
->withExceptions(function (Exceptions $exceptions) {
// 1. 调整日志等级
$exceptions->level(PaymentException::class, Psr\Log\LogLevel::WARNING);
// 2. 忽略不需要记录日志的异常
$exceptions->dontReport([
MissingTokenException::class,
]);
// 3. 自定义特定异常的返回格式
$exceptions->render(function (AccountSuspendedException $e) {
return response()->json(['message' => '您的账号已被冻结。'], 403);
});
})