Laravel 13 异常处理详解 异常处理是应用程序健壮性的重要保障。Laravel 13 提供了强大而灵活的异常处理机制,帮助开发者优雅地处理各种错误情况。
异常处理器 全局异常处理器 1 2 3 4 5 6 use App \Exceptions \Handler ;->withExceptions (function (Exceptions $exceptions ) { })
自定义异常处理器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?php namespace App \Exceptions ;use Illuminate \Foundation \Exceptions \Handler as ExceptionHandler ;use Throwable ;class Handler extends ExceptionHandler { protected $dontFlash = [ 'current_password' , 'password' , 'password_confirmation' , ]; protected $dontReport = [ \Illuminate\Auth\AuthenticationException ::class , \Illuminate\Auth\Access\AuthorizationException ::class , \Symfony\Component\HttpKernel\Exception\HttpException ::class , \Illuminate\Database\Eloquent\ModelNotFoundException ::class , \Illuminate\Validation\ValidationException ::class , ]; public function register ( ): void { $this ->reportable (function (Throwable $e ) { if (app ()->bound ('sentry' )) { app ('sentry' )->captureException ($e ); } }); } }
报告异常 report 方法 1 2 3 4 5 6 7 8 9 10 11 12 use Throwable ;use Illuminate \Support \Facades \Log ;public function report (Throwable $exception ) { if ($exception instanceof CustomException) { Log ::channel ('custom' )->error ($exception ->getMessage ()); return ; } parent ::report ($exception ); }
可报告异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public function register ( ): void { $this ->reportable (function (PaymentFailedException $e ) { Log ::channel ('payments' )->error ('Payment failed' , [ 'order_id' => $e ->orderId, 'amount' => $e ->amount, 'error' => $e ->getMessage (), ]); }); $this ->reportable (function (Throwable $e ) { if (app ()->environment ('production' )) { app ('sentry' )->captureException ($e ); } })->stop (); }
异常级别 1 2 3 4 5 6 7 8 9 10 11 protected $levels = [ \Psr\Log\LogLevel ::CRITICAL => [ \App\Exceptions\PaymentFailedException ::class , ], \Psr\Log\LogLevel ::ERROR => [ \Illuminate\Database\QueryException ::class , ], \Psr\Log\LogLevel ::WARNING => [ \App\Exceptions\RateLimitExceededException ::class , ], ];
渲染异常 render 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public function render ($request , Throwable $exception ) { if ($exception instanceof CustomException) { return response ()->json ([ 'message' => $exception ->getMessage (), 'code' => $exception ->getCode (), ], 400 ); } if ($exception instanceof ModelNotFoundException) { return response ()->json ([ 'message' => 'Resource not found' , ], 404 ); } return parent ::render ($request , $exception ); }
可渲染异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public function register ( ): void { $this ->renderable (function (OrderNotFoundException $e , Request $request ) { if ($request ->expectsJson ()) { return response ()->json ([ 'message' => 'Order not found' , 'order_id' => $e ->orderId, ], 404 ); } return redirect ()->route ('orders.index' ) ->with ('error' , 'Order not found' ); }); $this ->renderable (function (ValidationException $e , Request $request ) { if ($request ->expectsJson ()) { return response ()->json ([ 'message' => 'Validation failed' , 'errors' => $e ->errors (), ], 422 ); } }); }
自定义异常 创建自定义异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?php namespace App \Exceptions ;use Exception ;class PaymentFailedException extends Exception { public function __construct ( public string $orderId , public float $amount , string $message = 'Payment failed' , int $code = 0 ) { parent ::__construct ($message , $code ); } public function context ( ): array { return [ 'order_id' => $this ->orderId, 'amount' => $this ->amount, ]; } public function report ( ): void { Log ::channel ('payments' )->error ('Payment failed' , $this ->context ()); } public function render ($request ) { if ($request ->expectsJson ()) { return response ()->json ([ 'message' => $this ->getMessage (), 'order_id' => $this ->orderId, ], 400 ); } return back ()->with ('error' , $this ->getMessage ()); } }
抛出自定义异常 1 2 3 4 5 6 7 8 9 use App \Exceptions \PaymentFailedException ;if (!$payment ->isSuccessful ()) { throw new PaymentFailedException ( orderId: $order ->id, amount: $order ->total, message: 'Payment declined by provider' ); }
HTTP 异常 使用 abort 辅助函数 1 2 3 abort (404 );abort (403 , 'Unauthorized action' );abort (404 , 'Page not found' , ['custom' => 'data' ]);
自定义 HTTP 异常页面 1 2 3 4 5 6 7 8 9 10 @extends ('layouts.app' ) @section ('content' ) <div class ="text -center "> <h1 >404</h1 > <p >Page not found </p > <a href =" {{ url ('/' ) }}">Go Home</a> </div> @endsection
自定义异常响应 1 2 3 4 5 6 7 8 ->withExceptions (function (Exceptions $exceptions ) { $exceptions ->render (function (NotFoundHttpException $e , Request $request ) { if ($request ->expectsJson ()) { return response ()->json (['message' => 'Resource not found' ], 404 ); } }); })
验证异常 处理验证异常 1 2 3 4 5 6 7 8 9 10 11 use Illuminate \Validation \ValidationException ;public function register ( ): void { $this ->renderable (function (ValidationException $e , Request $request ) { return response ()->json ([ 'message' => 'Validation failed' , 'errors' => $e ->errors (), ], 422 ); }); }
自定义验证异常 1 2 3 4 throw ValidationException ::withMessages ([ 'email' => ['The email must be a valid email address.' ], 'password' => ['The password must be at least 8 characters.' ], ]);
异常上下文 添加上下文信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php namespace App \Exceptions ;use Exception ;class OrderProcessingException extends Exception { protected array $context ; public function __construct (string $message , array $context = [] ) { parent ::__construct ($message ); $this ->context = $context ; } public function context ( ): array { return $this ->context; } } throw new OrderProcessingException ( 'Failed to process order' , ['order_id' => $order ->id, 'step' => 'payment' ] );
异常日志 记录异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 use Illuminate \Support \Facades \Log ;try { $result = $service ->process (); } catch (Exception $e ) { Log ::error ('Processing failed' , [ 'exception' => get_class ($e ), 'message' => $e ->getMessage (), 'file' => $e ->getFile (), 'line' => $e ->getLine (), 'trace' => $e ->getTraceAsString (), ]); throw $e ; }
异常通知 1 2 3 4 5 6 7 public function register ( ): void { $this ->reportable (function (CriticalException $e ) { Notification ::route ('mail' , 'admin@example.com' ) ->notify (new CriticalExceptionNotification ($e )); }); }
异常处理最佳实践 1. 使用特定异常 1 2 3 4 5 6 7 8 throw new OrderNotFoundException ($orderId );throw new PaymentFailedException ($orderId , $amount );throw new InsufficientStockException ($productId , $requested , $available );throw new Exception ('Order not found' );throw new Exception ('Payment failed' );
2. 提供有意义的错误信息 1 2 3 4 5 6 7 throw new ValidationException ('The email address is already registered.' , [ 'email' => ['This email is already taken.' ] ]); throw new ValidationException ('Validation failed' );
3. 使用异常上下文 1 2 3 4 5 6 7 8 9 10 throw new PaymentFailedException ( message: 'Payment declined' , orderId: $order ->id, amount: $order ->total, provider: 'stripe' ); throw new PaymentFailedException ('Payment declined' );
4. 合理使用异常层级 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php namespace App \Exceptions ;class ApplicationException extends Exception {}class OrderException extends ApplicationException {}class OrderNotFoundException extends OrderException {}class PaymentException extends ApplicationException {}class PaymentFailedException extends PaymentException {}
测试异常 测试异常抛出 1 2 3 4 5 6 7 8 public function test_order_not_found_exception ( ): void { $this ->expectException (OrderNotFoundException ::class ); $this ->expectExceptionMessage ('Order not found' ); $service = new OrderService (); $service ->find (999 ); }
测试异常响应 1 2 3 4 5 6 7 8 9 public function test_exception_returns_json_response ( ): void { $response = $this ->getJson ('/api/orders/999' ); $response ->assertStatus (404 ) ->assertJson ([ 'message' => 'Order not found' , ]); }
总结 Laravel 13 的异常处理系统提供了强大而灵活的错误处理能力。通过合理使用自定义异常、异常报告和渲染机制,可以构建出健壮、用户友好的应用程序。记住使用特定异常类型、提供有意义的错误信息、添加上下文数据,并遵循异常处理最佳实践。在生产环境中,确保敏感信息不会被泄露,并使用适当的日志级别记录异常。