Blog / Créer une page d’erreur personnalisée avec Laravel et Inertia

Image used for article Créer une page d’erreur personnalisée avec Laravel et Inertia

Créer une page d’erreur personnalisée avec Laravel et Inertia




TL;DR: Comment afficher une page d’erreur personnalisée avec Inertia au lieu des erreurs par défaut de Laravel.




Vous trouverez un projet Laravel d’exemple sur ce Github Repository. Découvrez en plus sur Capsules ou X.




Dans un article précédent, le quatrième article de ce blog. il était question de personnaliser la page d’erreur 502 Bad Gateway servie par Nginx. Celle-ci était une page HTML placée directement dans le dossier /public. Cet article se concentre désormais sur la personnalisation des pages d’erreur retournées par Laravel dans un projet VILT.




Pour avoir un aperçu du layout des pages d’erreur Laravel, il suffit de générer une erreur en utilisant la Facade App::abort ou le helper abort, suivi du code d’erreur désiré.



routes/web.php


<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\App;


Route::get( '/', fn() => App::abort( 503 ) );








Route::get( '/', fn() => App::abort( 419 ) );







Route::get( '/', fn() => App::abort( 404 ) );







En approfondissant le fonctionnement de la fonction abort, force est de constater que Laravel génère une Exception, laquelle est ensuite traitée par le ExceptionHandler créé par la méthode withExceptions() dans le fichier bootstrap/app.php .



vendor/laravel/framework/src/Illuminate/Foundation/Application.php


public function abort($code, $message = '', array $headers = [])
{
    if ($code == 404) {
        throw new NotFoundHttpException($message, null, 0, $headers);
    }

    throw new HttpException($code, $message, null, $headers);
}



vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php


protected function prepareResponse($request, Throwable $e)
{
    if (! $this->isHttpException($e) && config('app.debug')) {
        return $this->toIlluminateResponse($this->convertExceptionToResponse($e), $e)->prepare($request);
    }

    if (! $this->isHttpException($e)) {
        $e = new HttpException(500, $e->getMessage(), $e);
    }

    return $this->toIlluminateResponse(
        $this->renderHttpException($e), $e
    )->prepare($request);
}



bootstrap/app.php


<?php

use Illuminate\Foundation\Application;

return Application::configure( basePath : dirname( __DIR__ ) )
    ->withRouting( web : base_path( "/routes/web.php" ) )
    ->withExceptions()
    ->create();

  • Si la méthode withExceptions est retirée du fichier, plus rien ne fonctionne. Il est donc crucial de ne pas négliger cette méthode.




Pour permettre à Inertia d’intercepter à son tour les différentes exceptions, il est nécessaire de modifier le fichier bootstrap/app.php. C’est principalement dans ce fichier que la magie opère.




Et plus particulièrement au niveau de la méthode withExceptions : l’interception des exceptions. Lorsque l’exception est un HttpException, ce qui est l’objet de cet article, le rendu Inertia est déclenché. La méthode $exceptions->render( fn( HttpException $exception, ... ) permet de filtrer les types d’exception. Si l'exception est une HttpException, le processus de rendu Inertia se poursuit. Inertia retourne alors la page Error avec la réponse $request et son code de status.



bootstrap/app.php


<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Http\Request;
use Inertia\Inertia;


return Application::configure( basePath : dirname( __DIR__ ) )
    ->withRouting( web : base_path( "/routes/web.php" ) )
    ->withExceptions( fn( Exceptions $exceptions ) =>

        $exceptions->render( fn( HttpException $exception, Request $request ) =>

            Inertia::render( 'Error', [ 'status' => $exception->getStatusCode() ] )
                   ->toResponse( $request )
                   ->setStatusCode( $exception->getStatusCode() )

        )
    )
    ->create();




Il est alors possible de personnaliser les pages d'erreur souhaitées en utilisant un composant Vue Error dédié aux erreurs.



resources/js/pages/Error.vue


<script setup>

import { Head } from '@inertiajs/vue3'
import { useStatusName, useStatusMessage } from '~/composables/status';
import logotype from '/public/assets/capsules-logotype.svg';


const props = defineProps( { status : Number } );

</script>

<template>

    <Head>

        <title>{{ useStatusName( status ) }}</title>

    </Head>

    <div class="h-screen flex justify-center">

        <div class="flex items-center space-x-10">

            <img class="h-20 w-20" v-bind:src="logotype">

            <div class="flex flex-col items-start space-y-2 font-mono text-primary-black">

                <h1 class="text-2xl text-primary-blue" v-text="`${props.status} - ${useStatusName( status )}`" />

                <p class="text-md" v-text="useStatusMessage( status )" />

            </div>

        </div>

    </div>

</template>
  • Le composant Head permet de personnaliser la section <head> de la page HTML. Il ne faut cependant pas oublier d’inclure @inertiaHead dans le fichier app.blade.php




Ainsi qu’un composable status qui retourne les codes et messages d’erreur recherchés.



resources/js/composables/status.js


export function useStatusName( status )
{
    switch( status )
    {
        case 503 : return 'Service Unavailable';
        case 500 : return 'Server Error';
        case 419 : return 'Page Expired';
        case 418 : return 'I\'m a teapot';
        case 404 : return 'Not Found';
        case 403 : return 'Forbidden';
        default : return 'Error';
    }
}


export function useStatusMessage( status )
{
    switch( status )
    {
        case 503 : return 'Sorry, we are doing some maintenance. Please check back soon.';
        case 500 : return 'Whoops, something went wrong on our servers.';
        case 419 : return 'Sorry, your page expired.';
        case 418 : return 'Sorry, I am not a coffee machine.';
        case 404 : return 'Sorry, the page you are looking for could not be found.';
        case 403 : return 'Sorry, you are forbidden from accessing this page.';
        default : return 'Sorry, something went wrong unexpectedly.';
    }
}




Pour tester les différentes exceptions directement depuis le navigateur :



routes/web.php


<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\App;


Route::get( '/{status?}', fn( int | null $status = null ) => App::abort( $status ?? 418 ) );


herd link article

npm run dev




> http://article.test/503





> http://article.test/419





> http://article.test/404





Ravi d’avoir pu aider !

v1.3.1

Icône XIcône Github