Laravel 5.6 - how to implement 404 page/route - laravel

I am trying to implement 404 page, but so far nothing is happening. I am getting this:
Not Found
The requested URL /test was not found on this server.
I have custom 404 page with completely different text.
In my routes file I have this route:
Route::fallback(function(){
return response()->view('errors/404', [], 404);
});
In Handler.php I added this:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
if ($exception instanceof MethodNotAllowedHttpException)
abort(404);
if ($this->isHttpException($exception)) {
if ($exception->getStatusCode() == 404) {
return response()->view('errors.404', [], 404);
}
}
return parent::render($request, $exception);
}
The 404.blade.php is located under the resources/view/errors

The 404.blade.php file should be located under resources/views/errors (note the 's' in views). And you don't need that custom code in your routes and Handler.php files, Laravel can handle 404's by itself.

The error message
Not Found
The requested URL /test was not found on this server.
is the default server 404 error message and not from Laravel.
You are supposed to see Laravel's default error page when you don't configure custom error pages.
This means that you might not have configured rewrite properly on your server and Laravel did not get the request.
You can check out this post on how to enable mod_rewrite on apache

in handler.php immport
use Illuminate\Session\TokenMismatchException;
and edit the render() function to following
public function render($request, Exception $exception)
{
if ($exception instanceof TokenMismatchException) {
if ($request->expectsJson()) {
return response()->json([
'dismiss' => __('Session expired due to inactivity. Please reload page'),
]);
}
else{
return redirect()->back()->with(['dismiss'=>__('Session expired due to inactivity. Please try again')]);
}
}
elseif($exception->getStatusCode()!=422){
return response()->view('errors.404');
}
return parent::render($request, $exception);
}
This is how you will be redirected to 404 page on any error.
TokenMismatchException is session expiration and status code 422 is validation error. Here $request->expectsJson() is for ajax json process

Related

Catch FTP Laravel exceptions

I'm trying to work for the first time with Laravel exceptions handling.
What I need is to catch the different exceptions I get when trying to connect to FTP server (eg. cannot connect, wrong user/password, cannot find new files, cannot open files).
I'm stuck because I see that Laravel already has a class that throw Exceptions (located in vendor/league/flysystem/src/Adapted/Ftp.php) and the Handler.php but I don't understand how they work together and how I can render different messages depending on Exception.
Many thanks for your help.
The Handler.php will encapsule any call and handle any exception that extend the native class \Exception of PHP. So, no matter where the exception is triggered, the handler will try to handle it.
You can customize the response in two ways.
Catch the exception before the handler:
Basicly, surround the line of code that can trigger an exception with a try catch
try {
connectFTP();
} catch (\Exception $e) { //better use FilesystemException class in your case
//handle it
}
Adapt the Handler.php: Here there are two ways:
Patch : just intercept in the render method the exception in question
Handler.php laravel 8.x (add the method)
public function render($request, Exception $e)
{
if ($e instance of \FtpException) {
//handle it here
}
parent::render($request, $e);
}
Use your own exception class:More info here
class FtpConnectionException extends Exception
{
/**
* Report the exception.
*
* #return bool|null
*/
public function report()
{
//
}
/**
* Render the exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function render($request)
{
return response(...);
}
}
How can you use your own exception class when the exception is triggered in the Vendor folder ? use the try catch method
try {
connectFTP();
} catch (\Exception $e) { //better use FilesystemException class in your case
throw new FtpConnectionException($e->getMessage(), $e->getCode(), $e->getPrevious());
}
NOTE: Some exceptions dont reach the Handler.php like the CSRF 419 exception and the 404 page not found exception.

How can I change the text on the 404 not found view in Laravel?

I'm setting up an API with Laravel. When I enter a route that does not exist I get redirected to a view that says 404 | Not found.
How could I change this view to abort( response()->json('Not Found', 404)); so that the person that tries to access the API via another application get a JSON response saying Not Found.
You may publish Laravel's error page templates using the
vendor:publish Artisan command. Once the templates have been
published, you may customize them to your liking:
php artisan vendor:publish --tag=laravel-errors
You only need to create a 404.blade.php file under resources/views/errors/ with whatever content and style you want. I've just done that...
Otherwhise
define a fallback route at the end of the routes/api.php file:
Route::fallback(function(){
return response()->json(['message' => 'Not Found.'], 404);
})->name('api.fallback.404');
Source
Try these steps:
1) In the app/Exceptions/Handler.php file, modify the render method.
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
if ($this->isHttpException($exception)) {
if ($exception->getStatusCode() == 404) {
return response()->view('errors.' . '404', [], 404);
}
}
return parent::render($request, $exception);
}
2) Create a new view file errors/404.blade.php.
<!DOCTYPE html>
<html>
<head>
<title>Page not found - 404</title>
</head>
<body>
The page your are looking for is not available
</body>
</html>

Laravel API returns a view 404 error instead of JSON error

I am trying to create a RESTful API using laravel, I'm trying to fetch a resource with an invalid ID, and the result is 404 since it is not found, but my problem is the response is not in JSON format, but a View 404 (by default) with HTML. Is there any way to convert the response into JSON? For this situation, I use Homestead.
I try to include a fallback route, but it does not seem to fit this case.
Route::fallback(function () {
return response()->json(['message' => 'Not Found.'], 404);
});
I try to modify the Handler (App\Exceptions), but nothing change.
public function render($request, Exception $e)
{
if ($e instanceof ModelNotFoundException) {
if ($request->ajax()) {
return response()->toJson([
'message' => 'Not Found.',
], 404);
}
}
return parent::render($request, $e);
}
For Laravel 9
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Register the exception handling callbacks for the application.
*
* #return void
*/
public function register()
{
$this->renderable(function (NotFoundHttpException $e, $request) {
if ($request->is('api/*')) {
return response()->json([
'message' => 'Record not found.'
], 404);
}
});
}
You'll need to send the correct Accept header in your request: 'Accept':'application/json'.
Then Illuminate\Foundation\Exceptions\Handler will care of the formatting in the render method in your response:
return $request->expectsJson()
? $this->prepareJsonResponse($request, $e)
: $this->prepareResponse($request, $e);
if your project is only a RESTful API and no views, you could add a new middleware which add ['accept' => 'application/json'] header to all request. this will ensure that all response will return a json, instead of the views
<?php
namespace App\Http\Middleware;
use Closure;
class AddAjaxHeader
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$request->headers->add(['accept' => 'application/json']);
return $next($request);
}
}
and add it into Kernel.php
You need to set APP_DEBUG in you .env file to false.
or, if you use a phpunit, like follows
config()->set('app.debug', false);
In Laravel 9, as per Official Documentation ModelNotFoundException is directly forwarded to NotFoundHttpException (which is a part of Symfony Component) that used by Laravel and will ultimately triggers a 404 HTTP response.
so, we need to checking Previous Exception using $e->getPrevious() just check previous exception is instanceof ModelNotFoundException or not
see below my code
// app/Exceptions/Handler.php file
$this->renderable(function (NotFoundHttpException $e, $request) {
if ($request->is('api/*')) {
if ($e->getPrevious() instanceof ModelNotFoundException) {
/** #var ModelNotFoundException $modelNotFound */
$modelNotFound = $e->getPrevious();
if($modelNotFound->getModel() === Product::class) {
return response()->json([
'message' => 'Product not found.'
], 404);
}
}
return response()->json([
'message' => 'not found.'
], 404);
}
});
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Symfony\Component\HttpFoundation\Response
*
* #throws \Throwable
*/
public function render($request, Throwable $exception)
{
switch (class_basename($exception)) {
case 'NotFoundHttpException':
case 'ModelNotFoundException':
$exception = new NotFoundHttpException('Not found');
break;
}
return parent::render($request, $exception);
}

get current request in 404 page

Hey I want to use the current request object as the facade not the static way($request not Request::) in a custom 404 blade file.
I don't know if I can hint about it to the error handler or is there a way to create that object?
Should/Could I do it via the Expections/Handler.php file?
I've found Here the following answer:
//Create a view and set this code in app/Exception/Handler.php :
/**
* Render an exception into a response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $e
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if($e instanceof NotFoundHttpException)
{
return response()->view('missing', [], 404);
}
return parent::render($request, $e);
}
//Set this use to get it working :
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Is this the right way to do it?
Yes, you can do it from the Handler. Inside the render() method:
if ($e instanceof NotFoundHttpException) {
return response()->view('your.view.name', $dataYouWantToPass);
}

Laravel - 404 error handling for different route groups

I want to show two types of 404 error screen for users, authenticated users with admin rights inside the route /admin see an error page style and unauthenticated guests in the route/see another error page, how can I do this?
You can use the Exception Handler's render() method. From the documentation,
The render method is responsible for converting a given exception into
an HTTP response that should be sent back to the browser.
Instead of returning same views for all users, you can add the authorization logic in the App\Exceptions\Handler calss:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $e
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if ($e instanceof CustomException) {
if(isAdmin()) {
return response()->view('admin.errors.custom', [], 500);
}
return response()->view('errors.custom', [], 500);
}
return parent::render($request, $e);
}

Resources