Reputation: 2031
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?
Upvotes: 9
Views: 5617
Reputation: 1029
For Laravel 5.5.5 or above just use the Route::fallback:
Route::fallback('PagesController@notFound');
this will help you to customize your 404 views having access to all the session, and more, stuff.
Upvotes: 3
Reputation: 2716
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' => 'HttpErrorController@404',
'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
Upvotes: 0
Reputation: 2573
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);
}
}
Upvotes: 2
Reputation: 40653
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:
web
middleware run correctly for the requestThis 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.
Upvotes: 5
Reputation: 440
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
Upvotes: 3
Reputation: 223
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.
Upvotes: 14