Laravel异常处理程序


Laravel exceptions handler

我正在使用Laravel进行一个项目,异常在渲染函数内的Exceptions'Handler.php中被捕获,如下所示:

public function render($request, Exception $e){
      switch(get_class($e)){
              case SOME_EXCEPTION::class:
                    do something..
              ...
              ...
              default:
                    do something..
     }

你可以看到的问题是,在很多情况下,的代码变得丑陋和混乱

如何解决此问题?

如果您的自定义异常扩展了一个通用接口,您可以检查该接口,然后调用合约方法。

if ($e instanceof CustomExceptionInterface) {
    return $e->contractMethod();
}

好的,找到了一种让它看起来更好的方法。如果有人想在laravel中改进他的异常处理程序,请遵循以下内容:

在应用程序/提供商下创建您的新服务提供商,让我们称之为ExceptionServiceProvider.php

    class ExceptionServiceProvider extends ServiceProvider {
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(ExceptionFactory::class);
    }
    public function boot(ExceptionFactory $factory){
        $factory->addException(UnauthorizedException::class, JsonResponse::HTTP_NOT_ACCEPTABLE);
        $factory->addException(ConditionException::class, JsonResponse::HTTP_NOT_ACCEPTABLE, "Some Fixed Error Message");
    }
}

在项目的某个地方创建ExceptionFactory类,该类包含addException()方法和代码的getter&消息

class ExceptionFactory{

private $exceptionsMap = [];
private $selectedException;
public function addException($exception, $code, $customMessage = null) {
    $this->exceptionsMap[$exception] = [$code, $customMessage];
}
public function getException($exception){
    if(isset($this->exceptionsMap[$exception])){
        return $this->exceptionsMap[$exception];
    }
    return null;
}
public function setException($exception){
    $this->selectedException = $exception;
}
public function getCode(){
    return $this->selectedException[0];
}
public function getCustomMessage(){
    return $this->selectedException[1];
}

}

那么剩下的就是在Exceptions/handler.php内部在渲染函数中:

private $exceptionFactory;
    public function __construct(LoggerInterface $log, ExceptionFactory $exceptionFactory){
        parent::__construct($log);
        $this->exceptionFactory = $exceptionFactory;
    }
public function render($request, Exception $e){
        $error = new 'stdClass();
        $customException = $this->exceptionFactory->getException(get_class($e));
        if(isset($customException)){
            $this->exceptionFactory->setException($customException);
            $error->code = $this->exceptionFactory->getCode();
            $error->message = $e->getMessage();
            $customMessage = $this->exceptionFactory->getCustomMessage();
            if(isset($customMessage)){
                $error->message = $customMessage;
            }
       }
       return new JsonResponse($error, $error->code);
 }
}

最后要记住的是将ServiceProvider放在config/app.php下的应用程序设置中,只需添加:

'App'Providers'ExceptionServiceProvider::class

我希望你会发现这和我一样有用。

这是封面
  • Web
  • api
  • 日志查看器
  • 包异常处理程序
<?php
namespace App'Exceptions;
use Throwable;
use Illuminate'Support'Str;
use App'Traits'ApiResponser;
use Illuminate'Http'Request;
use Illuminate'Http'Response;
use Illuminate'Auth'AuthenticationException;
use Illuminate'Auth'Access'AuthorizationException;
use Illuminate'Http'Exceptions'HttpResponseException;
use League'OAuth2'Server'Exception'OAuthServerException;
use Illuminate'Http'Exceptions'ThrottleRequestsException;
use Symfony'Component'HttpKernel'Exception'HttpException;
use Saifur'FileManager'app'Facades'Helpers'SFMCommonFacade;
use Illuminate'Foundation'Exceptions'Handler as ExceptionHandler;
use Symfony'Component'HttpKernel'Exception'NotFoundHttpException;
use Symfony'Component'HttpKernel'Exception'MethodNotAllowedHttpException;
class Handler extends ExceptionHandler
{
    use ApiResponser;
    /**
     * A list of the exception types that are not reported.
     *
     * @var array<int, class-string<Throwable>>
     */
    protected $dontReport = [
        //
    ];
    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];
    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register()
    {
        $this->reportable(function (Throwable $e) {
            //
        });
    }
    public function report(Throwable $exception)
    {
        parent::report($exception);
    }
    protected function unauthenticated($request, AuthenticationException $exception)
    {
        return $this->set_response(null,401,'error',['Unauthenticated.']);
    }

    public function render($request, Throwable $e)
    {
        if ('config('app.debug'))  // debug mode => true error details is displayed
        {
            if (Str::startsWith(request()->getRequestUri(), '/log-viewer')) // for web + log viewer + debug mode route handler
            {
                return redirect('log-viewer/login');
            }
            return parent::render($request, $e);  // for web(except: /log-viewer) + api + debug mode route handler
        }
        // Processing the status code, exception ($e)
        $status = Response::HTTP_INTERNAL_SERVER_ERROR;
        [$status, $e, $message] = SFMCommonFacade::sfm_custom_exceptions($e);  // Saifur Package Exceptions
        if ($e instanceof HttpResponseException)
        {
            $status = Response::HTTP_INTERNAL_SERVER_ERROR;
        }
        elseif ($e instanceof MethodNotAllowedHttpException)
        {
            $status = Response::HTTP_METHOD_NOT_ALLOWED;
            $e = new MethodNotAllowedHttpException([], ('Method not allowed!'), $e);
        }
        elseif ($e instanceof NotFoundHttpException)
        {
            $status = Response::HTTP_NOT_FOUND;
            $e = new NotFoundHttpException(('Not found!'));
        }
        elseif ($e instanceof AuthorizationException)
        {
            $status = Response::HTTP_FORBIDDEN;
            $e = new AuthorizationException(('Forbidden request! You do not have the required permission to access.'), $status);
        }
        elseif ($e instanceof 'Dotenv'Exception'ValidationException && $e->getResponse())
        {
            $status = Response::HTTP_BAD_REQUEST;
            $e = new 'Dotenv'Exception'ValidationException(('Bad Request!'), $status, $e);
        }
        elseif ($e instanceof AuthenticationException)
        {
            $status = 401;
            $e = new HttpException($status, 'Unauthenticated!');
        }
        elseif ($e instanceof ThrottleRequestsException)
        {
            $retry_after = $e->getHeaders()['Retry-After'] ?? 0;
            $status = 429;
            $e = new HttpException($status, 'Too many requests! Try after '.$retry_after.' seconds!');
        }
        // Handle OAuth2 Server Exception
        elseif ($e instanceof OAuthServerException) {
            // Customize the error message based on the exception's properties
            $message = 'Access Denied: ' . $e->getMessage();
            $status = 403;
            $e = new HttpException($status, $message);
        }
        elseif ($e)
        {
            $e = new HttpException($status, $message ?? 'Internal Server Error!');
        }
        // Finally return the response
        if (Str::startsWith(request()->getRequestUri(), '/log-viewer') && $status == 401) // for web + log viewer route handler
        {
            return redirect('log-viewer/login');
        }
        else if (Str::startsWith(request()->getRequestUri(), '/api')) // for api route handler
        {
            return $this->set_response(null, $status, 'error', [$e->getMessage()]);
        }
        else{  // for web route handler
            return parent::render($request, $e);
        }
    }
}