Laravel 5.0 custom 404 does not use middleware

6.8k views Asked by At

I'm using a middleware to parse the output of the templates. This is working fine for all pages.

However when I want to show a 404 (got a custom page for that) it doesn't treat it as a http request (that's what I think) since it doesn't go through the middleware.

My question is, how to have ALL requests go through the middleware.

4

There are 4 answers

2
Björn On BEST ANSWER

The error pages don't go through the routes.php.

In Kernel.php move your middleware from the $routeMiddleware array to $middleware array.

Middleware in this array will run on every request (tested in 5.1).

Image showing middleware and a 404 page

0
AMIB On

At Laravel 5.4 and probably some older ones you can modify the file app/exceptions/Handler.php and the function render like this:

if( is_a( $exception, \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class ) ) {
    return redirect()->route( 'error_404' );
}

// ... old code in the function ...

in this way every 404 errors are redirected to certain real route that acts like other routes of site.

You may also submit any data from current request to show a reasonable error at the target.

0
Abdul Rehman On

I had a use case where api routes needs to always return json response.

All routes return json response (laravel checks through $request->expectsJson()) IF user specifically ask for it by sending accept: application/json header.

But many a times user doesn't send the header and they get an html response instead.

As for my use case, all api routes will always send json response we can force the routes to return json, by manually attaching accept: application/json header using a middleware.

App\Http\Middleware\ForceJsonOnAPIs.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Str;

class ForceJsonOnAPIs
{
    /**
     * Handle an incoming request.
     *
     * @param Request $request
     * @param Closure $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // Force Json accept type on api routes
        if ($request->is('api/*') && !Str::contains($request->header('accept'), ['/json', '+json'])) {
            $request->headers->set('accept', 'application/json,' . $request->header('accept'));
        }

        return $next($request);
    }
}

Register the middleware in App\Http\Kernel.php

// add the new middleware ForceJsonOnAPIs
protected $middleware = [
    \App\Http\Middleware\ForceJsonOnAPIs::class,

    // rest of the middleware,
];

Important: You can assign the middle to $middlewareGroups in Kernel like web or api, But you will get into trouble when 404 exception occurs. The issue is The error pages don't go through the routes.php (Thanks to @Björn Answer above) thus the routes middleware won't get called and the 404 will return html response.

It's the same case for validation or authentication exceptions.

In my opinion, it's best to assign the middleware in the $middleware array as it runs on each request. This way all exceptions will automatically return correct exceptions as json in all routes.

0
Ilya Sviridenko On

For people like me who spending hours in 2020 because of this weird behaviour...

Now in Laravel there is a new instrument «Fallback Routes».

Add this to /routes/web.php:

Route::fallback(function () {
    return view("404"); // template should exists
});

After that all requests will go throught middlewares.