Hello, I’m a Rocket

This is the second day of my participation in Gwen Challenge

The introduction

  • What is the Laravel framework for handling errors and exceptions
  • How to customize the exception response at work
  • How do I modify the exception Response page
  • Let’s take you to a deeper understanding

1. When to register custom exception and error handlers

Refer to my last article when the kernel is loaded upon startup

\Illuminate\Foundation\Bootstrap\HandleExceptions Registers the exception error handler

public function bootstrap(Application $app) { $this->app = $app; error_reporting(-1); set_error_handler([$this, 'handleError']); Set_exception_handler ([$this, 'handleException']); Register_shutdown_function ([$this, 'handleShutdown']); // If (! $app->environment('testing')) { ini_set('display_errors', 'Off'); }}Copy the code

Converts conforming errors into exception classes

public function handleError($level, $message, $file = '', $line = 0, $context = []) { if (error_reporting() & $level) { throw new ErrorException($message, 0, $level, $file, $line); }}Copy the code

Exception Handling report + output page

public function handleException($e) { if (! $e instanceof Exception) {// FatalThrowableError $e = new FatalThrowableError($e); } try { $this->getExceptionHandler()->report($e); } catch (Exception $e) { // } if ($this->app->runningInConsole()) { $this->renderForConsole($e); } else { $this->renderHttpResponse($e); } } protected function renderForConsole(Exception $e) { $this->getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); } protected function renderHttpResponse(Exception $e) { $this->getExceptionHandler()->render($this->app['request'], $e)->send(); }Copy the code

Listen for PHP script interrupts if there is an error and the error type contains convert from FatalErrorException and handle the exception

public function handleShutdown()
{
        if (! is_null($error = error_get_last()) && $this->isFatal($error['type'])) {
            $this->handleException($this->fatalExceptionFromError($error, 0));
        }
}

protected function isFatal($type)
{
        return in_array($type, [E_COMPILE_ERROR, E_CORE_ERROR, E_ERROR, E_PARSE]);
}

protected function fatalExceptionFromError(array $error, $traceOffset = null)
{
        return new FatalErrorException(
            $error['message'], $error['type'], 0, $error['file'], $error['line'], $traceOffset
       );
}
Copy the code

Get the exception handler

Protected function getExceptionHandler () {/ / get the exception handling app/Exceptions/Handler. PHP return $this->app->make(ExceptionHandler::class); }Copy the code

App/Exceptions/Handler. PHP framework extension exception classes

class Handler extends ExceptionHandler { public function report(Exception $exception) { parent::report($exception); } public function render($request, Exception $exception) { return parent::render($request, $exception); }}Copy the code

The base exception class of the Illuminate Foundation Exceptions Handler framework implements the interface Illuminate\Contracts Debug\ExceptionHandler

Public function report($e) {if ($this->shouldntReport($e)) {if ($this->shouldntReport($e)) { return; } // If (method_exists($e, 'report')) {return $e->report(); } try { $logger = $this->container->make(LoggerInterface::class); } catch (Exception $ex) { throw $e; $logger->error($e->getMessage(), array_merge($this->context(), ['exception' => $e])); } protected function shouldntReport(Exception $e) { $dontReport = array_merge($this->dontReport, $this->internalDontReport); return ! is_null(Arr::first($dontReport, function ($type) use ($e) { return $e instanceof $type; })); } protected function context() { try { return array_filter([ 'userId' => Auth::id(), 'email' => Auth::user() ? Auth::user()->email : null, ]); } catch (Throwable $e) { return []; }}Copy the code

Error output

Public function render($request, Exception $e) {// If (method_exists($e, 'render') && $response = $e->render($request)) { return Router::toResponse($request, $response); $e->toResponse($request); $e->toResponse($request); $e->toResponse($request); $e = $this->prepareException($e); if ($e instanceof HttpResponseException) { return $e->getResponse(); } elseIf ($e instanceof AuthenticationException) {return $this->unauthenticated($request, $e); } elseif ($e instanceof thrown) {/ / verification abnormal return $this - > convertValidationExceptionToResponse ($e, $request); } return $request->expectsJson() ? $this->prepareJsonResponse($request, $e) : $this->prepareResponse($request, $e); } protected function prepareException(Exception $e) { if ($e instanceof ModelNotFoundException) { $e = new NotFoundHttpException($e->getMessage(), $e); } elseif ($e instanceof AuthorizationException) { $e = new AccessDeniedHttpException($e->getMessage(), $e); } elseif ($e instanceof TokenMismatchException) {//csrf token $e = new HttpException(419, $e->getMessage(), $e); } return $e; }Copy the code

prepareJsonResponse

Protected function prepareJsonResponse($request, Exception $e) { return new JsonResponse( $this->convertExceptionToArray($e), $this->isHttpException($e) ? $e->getStatusCode() : 500, $this->isHttpException($e) ? $e->getHeaders() : [], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ); } protected function convertExceptionToArray(Exception $e) { return config('app.debug') ? [ 'message' => $e->getMessage(), 'exception' => get_class($e), 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => collect($e->getTrace())->map(function ($trace) { return Arr::except($trace, ['args']); })->all(), ] : [ 'message' => $this->isHttpException($e) ? $e->getMessage() : 'Server Error', ]; }Copy the code

prepareResponse

Protected function prepareResponse($request, Exception $e) {if (! $this->isHttpException($e) && config('app.debug')) {$this->isHttpException($e) && config('app.debug')) $this->toIlluminateResponse($this->convertExceptionToResponse($e), $e); } if (! $this->isHttpException($e)) { $e = new HttpException(500, $e->getMessage()); } return $this->toIlluminateResponse( $this->renderHttpException($e), $e ); } / / is mainly the debug = true when protected function convertExceptionToResponse (Exception $e) {return SymfonyResponse: : create ( $this->renderExceptionContent($e), $this->isHttpException($e) ? $e->getStatusCode() : 500, $this->isHttpException($e) ? $e->getHeaders() : [] ); } protected function renderExceptionContent(Exception $e) {try {//debug returns config('app.debug') && class_exists(Whoops::class) ? $this->renderExceptionWithWhoops($e) : $this->renderExceptionWithSymfony($e, config('app.debug')); } catch (Exception $e) { return $this->renderExceptionWithSymfony($e, config('app.debug')); Function renderHttpException(HttpException $e) {// Register the error page $this->registerErrorViewPaths(); If (view()->exists($view = "errors::{$e->getStatusCode()}")) {return response()->view($view, $view) [ 'errors' => new ViewErrorBag, 'exception' => $e, ], $e->getStatusCode(), $e->getHeaders()); } return $this->convertExceptionToResponse($e); }Copy the code

2. Flow chart

3. How to ignore exceptions

Added to the dontReport

4. Write the error to the log

It is written to the log during the report

5. Customize the exception response

Implement PHP Exception, can define their own report and render

6. Modify the error page

Refer to point 7 to register the error page to the view

7, you can customize the method inapp/Exceptions/Handler.php

Unauthenticated Handles unauthorized exceptions

Protected function unauthenticated($request, AuthenticationException $exception) {your logic}Copy the code

ConvertValidationExceptionToResponse validation class exception handling

Protected function convertValidationExceptionToResponse (thrown $e, $request) logical} {youCopy the code

RegisterErrorViewPaths Registers error pages to views

Protected function registerErrorViewPaths() {your logic should look at view processing}Copy the code

8. How to debug gracefully online (without tuning error logs and filtering)

Set class member protected $debug=false; public function __construct(Container $container) { $this->container = $container; $this->debug = isset($_GET['debug'])? $_GET['debug'] == 'h5debug':config('app.debug'); } protected function prepareResponse($request, Exception $e) { if (! $this->isHttpException($e) && $this->debug) $this->toIlluminateResponse($this->convertExceptionToResponse($e), $e); } if (! $this->isHttpException($e)) { $e = new HttpException(500, $e->getMessage()); } return $this->toIlluminateResponse( $this->renderHttpException($e), $e ); } protected function renderExceptionContent(Exception $e) {try {//debug returns $this->debug && when true class_exists(Whoops::class) ? $this->renderExceptionWithWhoops($e) : $this->renderExceptionWithSymfony($e, config('app.debug')); } catch (Exception $e) { return $this->renderExceptionWithSymfony($e, config('app.debug')); Protected function convertExceptionToArray(Exception $e) {return $this->debug? [ 'message' => $e->getMessage(), 'exception' => get_class($e), 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => collect($e->getTrace())->map(function ($trace) { return Arr::except($trace, ['args']); })->all(), ] : [ 'message' => $this->isHttpException($e) ? $e->getMessage() : 'Server Error', ]; }Copy the code

At the end

With you mutual encouragement, I hope to help you