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)