I am new to Laravel and I'm trying to catch any requests that do not match existing routes. Currently I am getting a ...
Symfony \ Component \ HttpKernel \ Exception \ NotFoundHttpException
I have created an App::missing() handler in the app/start/global.php as described on the documentation page but that doesn't help. I also tried creating an App::error(function(NotFoundHttpException $exception, $code) handler, but that didn't help either.
Any help would be appreciated.
You need this: In 'app/start/global.php' add:
App::missing(function($exception)
{
return Response::view('errorView', array(), 404);
});
And of course in views create (in this case) errorView.blade.php
EDIT: This method handle all "404 Not Found" errors.
That's likely due to debugging being turned on in the app/config/app.php file. Try turning that value to false and see if your custom handler than 'handles" it.
Additionally, your error handler needs to return a Response in order to "short-circuit" the request and actually respond with the result of your error handler - Are you returning a value / Response class from your App::error() handler? (Please show us that code).
Here's an article on Laravel 4 Error Handling without outlines the process of how Laravel uses App::missing() and App::error() handlers when errors occur.
Pay specific attention to the "meat of the Handler class" section - it outlines how you need to return a value of some sort from the handler in order for it not to pass the Exception to the next handler (Likely your Whoops error output that displays when debug is set to true in app/config/app.php).
Here is how to throw a 404 error when a ModelNotFoundException occurs
App::error(function(Illuminate\Database\Eloquent\ModelNotFoundException $exception, $code)
{
return Response::view('errors.404', array(), 404);
});
in
app -> config -> app.php
if you make
'debug' => true,
to this
'debug' => false,
You will get an user experience environment which is other than the debugging mode. Please make sure you have checked it.
Thanks :)
I was able to make it works using the following code. I let 'debug' => true, in my local configuration.
In app/start/global.php
App::error(function(Symfony\Component\HttpKernel\Exception\NotFoundHttpException $exception)
{
Log::error($exception);
$response = Response::make(View::make('response')
->with('data', null)
->with('meta', 'Error, incorrect path')
->with('pagination', null));
$response->setStatusCode(404);
$response->header('content-type', 'application/json', true);
return $response;
});
If of any interest, the content of my view is
<?php
echo json_encode(array(
'data' => $data,
'pagination' => $pagination,
'meta' => $meta), JSON_PRETTY_PRINT);
?>
The main challenge was to use Symfony\Component\HttpKernel\Exception\NotFoundHttpException as the type of the Exception and not only NotFoundHttpException.
By using NotFoundHttpException, a 500 error was thrown.
Related
Since I started logging exceptions on a production site I'm noticing a lot of them, especially 404s, more than I would expect for a site with barely any traffic, and I'd like to get to the bottom of whether they're genuine users or just bots. To help with this, I want to capture the URL that the user was trying to visit before being redirected to the 404 route, so I can keep track of which non-existent routes are being mistakenly hit. I think I'm correct in assuming this URL should be available in the request, and that I just need to store the request and pass it through to the exception.
What's the best way to do this in Laravel 8 onwards?
Catch 404 exceptions in Handler(App\Exceptions\Handler).
If you see Rendering Exceptions
By default, the Laravel exception handler will convert exceptions into
an HTTP response for you. However, you are free to register a custom
rendering closure for exceptions of a given type. You may accomplish
this via the renderable method of your exception handler.
The closure passed to the renderable method should return an instance
of Illuminate\Http\Response, which may be generated via the response
helper. Laravel will deduce what type of exception the closure renders
by examining the type-hint of the closure:
so in the register method,call renderable
public function register()
{
$this->renderable(function (NotFoundHttpException $e, $request) {
Log::alert("404",[
"fullUrl"=>$request->fullUrl(),
"path"=>$request->path(),
"message" =>$e->getMessage()
]);
return response()->view('errors.404', [], $e->getStatusCode());
});
}
Also, don't forget to import and use
Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
EDIT: just a few hours of using this solution in production, with the benefit of the newly-added request URLs, has confirmed for me just how many of these HTTP 4xx errors are junk - mostly automated bots and maybe a few script kiddies trying common routes. For this reason I've added some logic to ignore 404 and 405 errors, and may still add others that mostly contribute noise to the logfile.
This was harder than it should have been, but this is the solution I'm currently using to log the request with all exceptions. It's probably not the cleanest way to do it, but it works perfectly for my needs. Thanks to John Lobo's answer for pointing me in the right direction.
It works by inspecting each instance of the Exception class and using PHP's instanceof to check whether it's a HTTP exception or not. If it is, it gets logged with the request URL and returns a view with a status code. If it's a generic non-HTTP exception, it gets logged with the request URL and returns another view with no status code (or you can keep the default exception behaviour by removing the return block, which renders a blank screen in production).
public function register()
{
$this->renderable(function (Exception $exception, $request) {
$url = $request->fullUrl();
if ($exception instanceof HttpException) {
$status = $exception->getStatusCode();
// Do not log HTTP 404 and 405s errors for reasons that will
// become apparent after a few hours of logging 404s and 405s
if(($status !== 404) && ($status !== 405)) {
Log::warning("Error $status occurred when trying to visit $url. Received the following message: " . $exception->getMessage());
}
return response()->view("errors.error", [
"exception" => $exception,
"status" => $status
],
$status
);
} else {
$status = $exception->getCode();
Log::warning("Exception $status occurred when trying to visit $url. Received the following message: " . $exception->getMessage());
return response()->view("errors.exception", [
"exception" => $exception,
"status" => $status
]);
}
});
// Optionally suppress all Laravel's default logging for exceptions, so only your own logs go to the logfile
$this->reportable(function (Exception $e) {
})->stop();
}
Currently have a POST route setup in Laravel
Route::post('/confirm', 'MainController#confirm');
'/confirm' makes use of some POST information sent over from the previous page.
What I am trying to accomplish is, if a user just types in 'index/confirm' into the url and not all of the POST info is present redirect to 'index'
I have the below code and cannot see why this would not work. I think it may be because inorder for the route to trigger at least some POST info needs to be present and if none is then error.
$input = $request->all();
if ( !isset($input) ) {
return redirect('');
}
Error message:
Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException
No message
/Users/&name/Desktop/$filepath/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php
protected function methodNotAllowed(array $others)
{
throw new MethodNotAllowedHttpException($others);
}
Commenters answered my question. Needed a seperate route for GET to handle unallowed user submitted url requests.
Route::get('/confirm', 'MainController#index');
That's fine for guarding one endpoint, but there's a more sweeping solution you can apply. Look to your App\Exceptions\Handler class. The render() method is given an awareness of the failed request, and the specific error that was thrown. public function render($request, Exception $e) .... Add this:
if ($e instanceof Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
return redirect('/index');
}
Just be careful with this. If you typo your redirect URL, you'll end up in an infinite loop. I'd also recommend an additional condition that respects the value of config('app.env') for debugging purposes.
Route::any('mobileLogin', ['as' => 'mobileLogin', 'uses' =>
'App\Controllers\LoginController#mobileLogin']);
For some reason my perfectly working route has stopped working and a "whoops" error is being shown using app/views/error-page.blade.php
Here is the controller function:
public function mobileLogin()
{
try
{
Log::info('----------------');
Log::info('Inside mobileLogin');
}
catch (\Exception $e)
{
Log::info('*********** ERROR**************');
Log::info('Message: ' . $e->getMessage());
Log::info('Trace String : ' . $e->getTraceAsString());
Log::info("*********** END of ERROR *************");
}
}
The /app/storage/logs/laravel.log don't show any error, hence trying to find what exactly went wrong.
In my config/app.php debug is set to true as well.
I've put log messages in my controller function as well, but it's failing before it even reaches there !
How does one debug this ?
If Laravel framework isn't routing to the controller itself, then where can I dig for the issue ?
Found the issue - it was an error in one of the php files itself.
I expected for a syntax error an error would show in the laravel.log, but no !
There is another error.log at the base of the app, which luckily had it !
I'm using Laravel 4 framework and I've defined a whole bunch of routes, now I wonder for all the undefined urls, how to route them to 404 page?
In Laravel 5.2. Do nothing just create a file name 404.blade.php in the errors folder , it will detect 404 exception automatically.
Undefined routes fires the Symfony\Component\HttpKernel\Exception\NotFoundHttpException exception which you can handle in the app/start/global.php using the App::error() method like this:
/**
* 404 Errors
*/
App::error(function(\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $exception, $code)
{
// handle the exception and show view or redirect to a diff route
return View::make('errors.404');
});
The recommended method for handling errors can be found in the Laravel docs:
http://laravel.com/docs/4.2/errors#handling-404-errors
Use the App::missing() function in the start/global.php file in the following manner:
App::missing(function($exception)
{
return Response::view('errors.missing', array(), 404);
});
according to the official documentation
you can just add a file in: resources/views/errors/
called 404.blade.php with the information you want to display on a 404 error.
I've upgraded my laravel 4 codebase to Laravel 5, for anyone who cares:
App::missing(function($exception) {...});
is NO LONGER AVAILABLE in Laravel 5, in order to return the 404 view for all non-existent routes, try put the following in app/Http/Kernel.php:
public function handle($request) {
try {
return parent::handle($request);
}
catch (Exception $e) {
echo \View::make('frontend_pages.page_404');
exit;
// throw $e;
}
}
I am trying to handle a few exceptions in Laravel 4, and the same snippet of code works for one of them but not for the others.
I declared an Exceptions.php file that I added to my composer.json.
In Exceptions.php, I declared the following:
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Class NotAllowedException extends Exception {};
The following handler, in Exceptions.php, works properly:
// snippet 1
App::error(function(NotAllowedException $e, $code, $needed)
{
return Response::make(View::make('special.error')->with('error', array('headline' => 'Not Allowed',
'description' =>'<p>Your user has not enough privileges to perform the requested operation.</p>')), 401);
});
When I try to do the same to handle HttpNotFoundExceptions and ModelNotFoundExceptions, the following 2 snippets which are copies of the first do not work and yield an Undefined variable: error error.
// snippet 2
App::error(function(ModelNotFoundException $e)
{
return Response::make(View::make('special.error')->with('error', array('headline' =>'Not Found',
'description' => '<p>It seems you have tried to access a page that does not exist.</p>')), 404);
});
// snippet 3
App::error(function(NotFoundHttpException $e)
{
return Response::make(View::make('special.error')->with('error', array('headline' =>'Not Found',
'description' => '<p>It seems you have tried to access a page that does not exist.</p>')), 404);
});
I was only able to make the NotFoundHttpException work by putting this into global.php:
App::missing(function($exception)
{
return Response::make(View::make('special.error')->with('error', array('headline' =>'Not Found',
'description' => '<p>It seems you have tried to access a page that does not exist.</p>')), 404);
});
But I do not know why it works if I put it there and it does not work if I put it in Exceptions.php.
Trying to put snippets 2 and 3 in global.php yield in both case an Internal Server error.
To recap, Questions:
I think I am following the ModelNotFoundException handling as per Laravel4's documentation; what What am I doing wrong / how to make it work?
why does the App::missing work only if I put it in global.php ? I fear that I might be missing something important about Laravel's inner workings.
Thanks in advance to anyone who can shed some light on those 2 issues