I use laravel 8 tried to edit my exceptions\handler.php
public function render($request, Throwable $exception)
{
if ($exception instanceof MethodNotAllowedHttpException) {
abort(404);
}
return parent::render($request, $exception);
}
but his gives not 404 but 500 when checking routes where MethodNotAllowedHttpException
One possible solution is to supply your routes/web.php file with a Route fallback. Try adding the following to the bottom of your web routes:
Route::fallback( function () {
abort( 404 );
} );
on Laravel 8 override default handler render function on App\Exceptions\Handler.php
public function render($request, Throwable $exception)
{
if ($exception instanceof MethodNotAllowedHttpException) {
if ($request->ajax() || $request->wantsJson() || $request->expectsJson()) {
//405 for Method Not Allowed
return response()->json(['error' => 'Bad Request'], 405);
}
else {
return parent::render($request, $exception);
}
}
}
don't forget to add use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;to test in Postman set key=>Accept ,value => application/json to test handler
reff: Return a 404 when wrong ttp request type used(e.g. get instead of post) in laravel
Related
I am developing a rest API and sometimes the frontend call an endpoint with the wrong HTTP request type. For example, I have a route (/users/unassigned) and the type of the route is "GET". Imagin my frontend call this route with a "POST" request. the following error occurs.
The POST method is not supported for this route. Supported methods: GET, HEAD, PUT, DELETE.
What I want is that the API response a JSON in these situations and I can handle the exception.I have used the Route::fallback but this method catch every exception of the routes. I need a function that only handles the told problem.
you can make some adjustment in your exception handler.
in app/Exceptions/Handler.php file's render function
public function render($request, Exception $exception)
{
if ($exception instanceof MethodNotAllowedHttpException) {
if ($request->ajax()) {
return response()->json(['error' => 'Route Not Found'], 404);
}
else {
//something else
}
}
return parent::render($request, $exception);
}
and add use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; at the top use section.
One way is to handle it with app/Exceptions/Handler.php:
public function render($request, Exception $e)
{
if ($request->ajax() || $request->wantsJson()) {
return response()->json([
'error' => $e->getMessage(),
], 400);
}
return parent::render($request, $e);
}
This will ouput the error message as json for all exceptions when the request is made by ajax or the request expect json.
You can also add a check for type of exception like this:
if ($exception instanceof MethodNotAllowedHttpException) {
// Code...
}
Thank you so much.
I use the following code in my handler.php.
{
if ($this->isHttpException($exception)) {
switch ($exception->getStatusCode()) {
// not authorized
case '403':
return Response()->json(["error" => "not authorized."],403);
break;
// not found
case '404':
return Response()->json(["error" => "Route not found."],404);
break;
// internal error
case '500':
return Response()->json(["error" => "internal error."],500);
break;
case '405':
return Response()->json(["error" => "request type not match."],405);
break;
default:
return $this->renderHttpException($exception);
break;
}
}
else {
return parent::render($request, $exception);
}
}
The main point is http code 405 for not allowed methodes. special thanks to #apokryfos.
Check what type of request you are getting in your $request variable, then handle it with condition.
change in your Handler.php
like
protected $dontReport = [
\Illuminate\Auth\AuthenticationException::class,
\Illuminate\Auth\Access\AuthorizationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
//
];
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
$arr = array("status" => 400, "message" =>"Unauthorized access", "data" => array());
return \Response::json($arr);
}
return redirect()->guest('login');
}
public function render($request, Exception $exception)
{
if ( $request->route()->getPrefix() == 'api' ) {
some code......
return response()->json($response, $status);
}
return parent::render($request, $exception);
}
I have a website content site & api both.
I want my exception return json when user request api
If user request is not api, it will return the default page.
But when I put logic into function render, the default one got error.
Anyone know how to fix this?
I'm not quite sure what your question is. But you can detect if you should return a JSON response or not using the wantsJson() method. For example the code should instead read to say:
public function render($request, Exception $exception)
{
if ( $request->wantsJson()) {
some code......
return response()->json($response, $status);
}
return parent::render($request, $exception);
}
Laravel should automatically detect this and return a JSON response for exceptions if you are making a JSON request. The fact it isn't doing this, I would check to make sure you are making a JSON request and not a standard HTTP request.
Use $request->wantsJson() and check if the route is prefixed with api:
public function render($request, Exception $exception)
{
if ( $request->wantsJson() && $request->is('api/*')) {
some code......
return response()->json($response, $status);
}
return parent::render($request, $exception);
}
See here for wantsJson() method, and other useful Request methods: https://laravel.com/api/5.7/Illuminate/Http/Request.html#method_wantsJson
how to redirect the page if the route doesn't exist like
'sitename.me/asdasdas'
because when I'm trying to do this
the NotFoundHttpException will show up.
please help me thanks
You can change the app/Exceptions/Handler.php for this purpose. Replace the render() and unauthenticated() function with the following.
public function render($request, Exception $exception) {
if ($this->isHttpException($exception)) {
switch ($exception->getStatusCode()) {
// not found
case 404:
return redirect()->guest(your redirect url));
break;
// internal error
case '500':
return redirect()->guest(your redirect url));
break;
default:
return $this->renderHttpException($exception);
break;
}
} else {
return parent::render($request, $exception);
}
}
protected function unauthenticated($request, AuthenticationException $exception) {
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
return redirect()->guest(your redirect url);
}
To redirect to external domains, use the following:
return redirect()->away('http://sitename.me/asdasdas');
To redirect to an internal URI, use:
return redirect('admin/dashboard');
To redirect to an application route, use:
return redirect()->route('admin.dashboard');
For further reference, have a look at the responses (redirects) documentation.
let me explain some details i have faced, Laravel throw common exception throw Handler.php file in app/Exceptions folder. In this file we have report function that throw common exception using render function.
public function report(Exception $exception)
{
if ($exception instanceof \League\OAuth2\Server\Exception\OAuthServerException){
$this->render(null,$exception);
} else {
parent::report($exception);
}
}
Above is an report function that throw any exception to render function specified below
public function render($request, Exception $exception)
{
if($exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException){
// return Helper::responseJson(null,'header','Page Not Found',404);
} else if ($exception instanceof ScopeHandler) {
return Helper::responseJson(null,'header','Unauthorized',401);
} else if ($exception instanceof \League\OAuth2\Server\Exception\OAuthServerException){
return Helper::responseJson(null,'token','Unauthorized',401);
} else if ($exception instanceof ModelNotFoundException) {
// return Helper::responseJson(null,'header','Model Not Found',404);
} else if ($exception instanceof \Illuminate\Database\QueryException){
// return Helper::responseJson(null,'header','Query Exception',400);
} else if ($exception instanceof \Swift_TransportException){
return Helper::responseJson(null,'header','Mail send Exception',400);
}else if ($exception instanceof ConnectionFailedException){
return Helper::responseJson(null,'header','Connection Exception',400);
}
/* else if($exception instanceof \Symfony\Component\Debug\Exception\FatalErrorException){
return Helper::responseJson(null,'header','PHP config Exception',400);
} */
return parent::render($request, $exception);
}
the above example of render function we used for throw exception using json format. we can redirect to specific page or we can do any functionality when these error thrown.
I'm working on a rest api project.
I was struggling with an issue. As I get the token expiration error, the generated code will be something like this :
public function authenticate(Request $request){
$this->checkForToken($request);
try {
if (! $this->auth->parseToken()->authenticate()) {
throw new UnauthorizedHttpException('jwt-auth', 'User not found');
}
} catch (JWTException $e) {
throw new UnauthorizedHttpException('jwt-auth', $e->getMessage(), $e, $e->getCode());
}
}
This code is written in this file :
vendor/tymon/jwt-auth/src/Http/Middleware/BaseMiddleware.php
How can I return this as a JSON type?
Catch that exception in your App\Exceptions\Handler class' render method and return a response formatted as json:
// Handler.php
// import the class of the exception you want to render a json response for at the top
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
...
public function render($request, Exception $exception)
{
// if your api client has the correct content-type this expectsJson()
// should work. if not you may use $request->is('/api/*') to match the url.
if($request->expectsJson())
{
if($exception instanceof UnauthorizedHttpException) {
return response()->json('Unauthorized', 403);
}
}
return parent::render($request, $e);
}
I need to have a custom controller triggered when user hits a not-existing url or when I programmatically force an App::abort(404).
How can I do it?
My 404 views need some data, and a simple blade View (or a ViewComposer) is not enough.
Thanks
PS catch-all urls is not functional, because they don't catch programmatically launched 404.
Edit the render function of App\Exceptions\Handler class and add something about 404 here:
if ($this->isHttpException($exception) && $this->getStatusCode() == 404) {
// Do what you want...
// You can even use the $request variable
}
Full example:
public function render($request, Exception $exception)
{
if ($this->isHttpException($exception) && $this->getStatusCode() == 404) {
echo 'hello from 404 renderer';
dd($request); // Or you can a view.
}
return parent::render($request, $exception);
}
Try to return a redirect() to your custom Controller instead of a response() from the Handler's render() method if the exception is 404. You can retrieve the the page requested from the $request then right ?
Here is the sample:
public function render($request, Exception $exception)
{
if ($this->isHttpException($exception) && $this->getStatusCode() == 404) {
return redirect(route('route.to.custom.controller'))->with('request', $request);
}
return parent::render($request, $exception);
}
Hope that will help, cheers !