DEV Community

Cover image for Laravel HTTP Error Custom Views (404, 403, 500, etc.)
Rafli Zocky
Rafli Zocky

Posted on • Originally published at Medium on

Laravel HTTP Error Custom Views (404, 403, 500, etc.)

How Laravel Handles HTTP Errors

  1. A request hits a non-existent route
  2. Router throws NotFoundHttpException
  3. Exception is caught by Handler
  4. Laravel looks for resources/views/errors/404.blade.php (example)
  5. Returns an HTTP 404 response with the rendered view

Common Handling

  • app/Exceptions/Handler.php : converts exceptions into HTTP responses.
<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Auth\Access\AuthorizationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * The list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->reportable(function (Throwable $e) {
            //
        });

        // 403 — Forbidden
        $this->renderable(function (AuthorizationException $e, $request) {
            if (!$request->expectsJson()) {
                return response()->view('errors.403', [], 403);
            }
        });

        // 404 — Not Found
        $this->renderable(function (NotFoundHttpException $e, $request) {
            if (!$request->expectsJson()) {
                return response()->view('errors.404', [], 404);
            }
        });

        // 419 — Page Expired (CSRF Token Mismatch)
        $this->renderable(function (TokenMismatchException $e, $request) {
            if (!$request->expectsJson()) {
                return response()->view('errors.419', [], 419);
            }
        });

        // 429 — Too Many Requests
        $this->renderable(function (ThrottleRequestsException $e, $request) {
            if (!$request->expectsJson()) {
                $retryAfter = $e->getHeaders()['Retry-After'] ?? 60;
                return response()->view('errors.429', ['retryAfter' => $retryAfter], 429);
            }
        });

        // 503 — Service Unavailable
        $this->renderable(function (ServiceUnavailableHttpException $e, $request) {
            if (!$request->expectsJson()) {
                return response()->view('errors.503', ['exception' => $e], 503);
            }
        });
    }

    public function render($request, Throwable $exception)
    {
        return parent::render($request, $exception);
    }
}
Enter fullscreen mode Exit fullscreen mode
  • resources/views/errors/{status_code}.blade.php
# example 
# resources\views\errors\404.blade.php

@extends('errors.layout')

@section('error_code', '404')

@section('error_content')
    <div class="text-center position-relative z-index-1" style="max-width: 520px;">

        {{-- Illustration --}}
        <div class="mb-6">
            <img src="{{ asset('assets/media/illustrations/unitedpalms-1/18.png') }}"
                 class="error-illustration theme-light-show" alt="404 Not Found" />
            <img src="{{ asset('assets/media/illustrations/unitedpalms-1/18-dark.png') }}"
                 class="error-illustration theme-dark-show" alt="404 Not Found" />
        </div>

        {{-- Title --}}
        <h1 class="fw-bold fs-2x text-gray-900 mb-3">Page Not Found</h1>

        {{-- Description --}}
        <p class="text-muted fs-5 mb-8 fw-semibold">
            Oops! The page you're looking for doesn't exist.<br>
            It may have been moved, deleted, or never existed.
        </p>

        {{-- Actions --}}
        <div class="error-actions d-flex gap-3 justify-content-center flex-wrap">
            <a href="{{ url()->previous() !== url()->current() ? url()->previous() : '/' }}"
               class="btn btn-light btn-lg fw-bold px-8">
                <i class="ki-duotone ki-arrow-left fs-2 me-2">
                    <span class="path1"></span><span class="path2"></span>
                </i>
                Go Back
            </a>
        </div>
    </div>
@endsection
Enter fullscreen mode Exit fullscreen mode

Then, just create simple routes to test it.

Route::get('/test-404', function () {
    abort(404);
});
Enter fullscreen mode Exit fullscreen mode

Also we can customize error pages by creating the views manually or publishing Laravel’s default templates:

php artisan vendor:publish — tag=laravel-errors
Enter fullscreen mode Exit fullscreen mode

Need help building your app? I’m available for freelance web & Android development — raflizocky.netlify.app

☕ Support my writing: paypal.me/raflizocky · saweria.co/raflizocky

Top comments (0)