Home » Php » php – Laravel 5: Sessions on 404 route

php – Laravel 5: Sessions on 404 route

Posted by: admin July 12, 2020 Leave a comment

Questions:

This is driving me crazy for weeks now:
How can I make sessions available on the 404 page? I just
embed the 404 error page in my default template. It also shows the navbar
and the footer but how can I keep my user logged in when on a 404?

On a 404 Auth::check() always returns false and every else whats session specific is null or empty.

How to enable sessions on (404) error pages?

How to&Answers:

What you can do is, inside the app/http/Kernel.php add the follwing block of code:

    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,

Inside the $middleware variable. So it would look like:

    protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    ];

It worked for me, I hope it works for you as well.

Answer:

So I know this is an old question but in case anyone finds it useful here’s how I’ve dealt with this:

In my App/Exceptions/Handler.php I changed the default render method to:

public function render($request, Exception $exception) {        
    \Route::any(request()->path(), function () use ($exception, $request) {
        return parent::render($request, $exception);
    })->middleware('web');
    return app()->make(Kernel::class)->handle($request);
}

This achieves 2 requirements:

  1. All the web middleware run correctly for the request
  2. Valid API routes do not start the session

This is in practice a decision to make the web middleware group the default to run when there’s an error. Laravel would normally not run any middleware group on error pages. You can of course specify additional middleware or other route parameters if you want or use other conditions like e.g. if the path starts with api/ then use the api middleware instead making it more consistent.

Hopefully this is helpful to someone.

Answer:

Just to expand a bit on the existing answer: make sure to remove that middleware from $middlewareGroups if it’s also there, so you don’t apply the middleware twice.

You’ll end up with something like this:

protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
];

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        //\Illuminate\Session\Middleware\StartSession::class,
        //\Illuminate\Session\Middleware\AuthenticateSession::class,
        //\Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],
];

As far as my understanding goes this was caused because the middleware that deals with the session, by being at the web group was being applied only to those pages routed on web.php. And since the default error handling does not redirect to a routed page we had no access to the session.

This way the middleware will be applied to all pages, and not only to those routed on web.php, including the error ones.

I originally found the soution here, but took me a while to understand why this was happening (thought i cold have gotten it all wrong, feel free to confirm or correct this please).

Hope it helps, it’s working for me on Laravel 5.4

Answer:

To avoid problems when you have other exception or recive request with api middleware,change the render function In App/Exceptions/Handler.php to :

 public function render ($request, Exception $exception)
{
    if ($this->isHttpException($exception)) {
        switch ($exception->getStatusCode()) {
            case '404':
                \Route::any(request()->path(), function () use ($exception, $request) {
                    return parent::render($request, $exception);
                })->middleware('web');
                return app()->make(Kernel::class)->handle($request);
                break;
            default:
                return $this->renderHttpException($exception);
                break;
        }
    } else {

        return parent::render($request, $exception);
    }
}

Answer:

I don’t really see how any of these answers are great. They are over complicated and tend to suggest to rebuild the kernel with an additional route, causing a spike in memory and cpu usage just to make a 404 page.

I suggest just creating the route you need, and not using the automatic error pages that the Laravel pages suggest. In newer versions of Laravel this has been improved, but for this version I just recommend the following:

routes.php

Route::group(['middleware' => ['web']], function ($router) {
    $router->get('/404', [
        'uses' => '[email protected]',
        'as' => 'errors.404',
    ]);
});

Obviously depending on how you are set up, this is how I’d use the routes and create a HttpErrorController to handle the route, this why it’s already in the web middleware group

App\Exceptions\Handler.php

public function render($request, Exception $exception) 
{

    if ($this->isHttpException($exception) && $exception->getStatusCode() === 404) 
    {
        return redirect()->route('404');
    }

    return parent::render($request, $exception);
}

You can handle these any way you see fit, add a switch in there, check if it’s a json request and then handle that differently etc

Answer:

For Laravel 5.5.5 or above just use the Route::fallback:

Route::fallback('[email protected]');

this will help you to customize your 404 views having access to all the session, and more, stuff.