Laravel如何实现适合Api的异常处理响应格式
前言
Laravel全局捕获异常后,会把异常转为相应的数据格式返回给用户。如果想要规定的数据格式相应,那我们只需重写异常捕获后的处理方法即可。
异常处理流程
Illuminate\Foundation\Exception\Handler中的render方法用来将异常转化为响应。
publicfunctionrender($request,Exception$e) { if(method_exists($e,'render')&&$response=$e->render($request)){ returnRouter::toResponse($request,$response); }elseif($einstanceofResponsable){ return$e->toResponse($request); } $e=$this->prepareException($e); if($einstanceofHttpResponseException){ return$e->getResponse(); }elseif($einstanceofAuthenticationException){ return$this->unauthenticated($request,$e); }elseif($einstanceofValidationException){ return$this->convertValidationExceptionToResponse($e,$request); } return$request->expectsJson() ?$this->prepareJsonResponse($request,$e) :$this->prepareResponse($request,$e); }
render()中又调用了prepareException()对部分异常进行预处理,但并未执行转化为响应的操作。
ModelNotFoundException一般在模型查找不到抛出,prepareException()中它被转为Symfony包中NotFoundHttpException,默认状态码404;
AuthorizationException在Policy权限未通过时抛出,prepareException()中它被转为Symfony包中AccessDeniedHttpException,默认状态码403;
TokenMismatchException在CSRF验证未通过时抛出,prepareException()中它被转为Symfony包中HttpException,给定状态码419;
其他异常直接返回。
protectedfunctionprepareException(Exception$e) { if($einstanceofModelNotFoundException){ $e=newNotFoundHttpException($e->getMessage(),$e); }elseif($einstanceofAuthorizationException){ $e=newAccessDeniedHttpException($e->getMessage(),$e); }elseif($einstanceofTokenMismatchException){ $e=newHttpException(419,$e->getMessage(),$e); } return$e; }
在回到render(),预处理异常之后,又分别对HttpResponseException、AuthenticationException和ValidationException单独处理,并转为响应返回。
除此以外的异常,都在prepareJsonResponse()或prepareResponse()处理,expectsJson()用来判断返回json响应还是普通响应。
修改异常响应格式
了解了异常处理流程,接下来就处理异常响应格式。
修改登录认证异常格式
由上文可知,AuthenticationException被捕获后,调用unauthenticated()来处理。
protectedfunctionunauthenticated($request,AuthenticationException$exception) { return$request->expectsJson() ?response()->json(['message'=>$exception->getMessage()],401) :redirect()->guest($exception->redirectTo()??route('login')); }
在appExceptionsHandler.php中重写unauthenticated()使其返回我们想要的数据格式。
protectedfunctionunauthenticated($request,AuthenticationException$exception) { return$request->expectsJson() ?response()->json([ 'code'=>0, 'data'=>$exception->getMessage(), ],401) :redirect()->guest($exception->redirectTo()??route('login')); }
修改验证异常格式
同样由上文可知,ValidationException被捕获后交由convertValidationExceptionToResponse()处理,进入此方法后我们需要继续追踪,若是需要json响应,最终交由invalidJson()处理。
protectedfunctionconvertValidationExceptionToResponse(ValidationException$e,$request) { if($e->response){ return$e->response; } return$request->expectsJson() ?$this->invalidJson($request,$e) :$this->invalid($request,$e); }
protectedfunctioninvalidJson($request,ValidationException$exception) { returnresponse()->json([ 'message'=>$exception->getMessage(), 'errors'=>$exception->errors(), ],$exception->status); }
我们继续在appExceptionsHandler.php重写invalidJson()即可自定义返回格式。
protectedfunctioninvalidJson($request,ValidationException$exception) { returnresponse()->json([ 'code'=>0, 'data'=>$exception->errors(), ],$exception->status); }
修改其他异常格式
其他异常是调用prepareJsonResponse()来处理,此方法又调用convertExceptionToArray()来处理响应格式。
protectedfunctionprepareJsonResponse($request,Exception$e) { returnnewJsonResponse( $this->convertExceptionToArray($e), $this->isHttpException($e)?$e->getStatusCode():500, $this->isHttpException($e)?$e->getHeaders():[], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES ); }
protectedfunctionconvertExceptionToArray(Exception$e) { returnconfig('app.debug')?[ 'message'=>$e->getMessage(), 'exception'=>get_class($e), 'file'=>$e->getFile(), 'line'=>$e->getLine(), 'trace'=>collect($e->getTrace())->map(function($trace){ returnArr::except($trace,['args']); })->all(), ]:[ 'message'=>$this->isHttpException($e)?$e->getMessage():'ServerError', ]; }
在appExceptionsHandler.php中重写convertExceptionToArray()来自定义其他异常响应格式。
protectedfunctionconvertExceptionToArray(Exception$e) { returnconfig('app.debug')?[ 'code'=>0, 'data'=>$e->getMessage(), 'exception'=>get_class($e), 'file'=>$e->getFile(), 'line'=>$e->getLine(), 'trace'=>collect($e->getTrace())->map(function($trace){ returnArr::except($trace,['args']); })->all(), ]:[ 'code'=>0, 'data'=>$this->isHttpException($e)?$e->getMessage():'ServerError', ]; }
强制json响应
代码中多次出现了expectsJson(),此方法是用来判断返回json响应还是普通响应。
publicfunctionexpectsJson() { return($this->ajax()&&!$this->pjax()&&$this->acceptsAnyContentType())||$this->wantsJson(); }
以下两种条件下,会返回json响应。
非XML请求、非pjax并且Headers中Accept设置为接收所有格式响应;
HeadersAccept设置为/json、+json。如:Accept:application/json。
除此之外的情况,将不会响应json。我们可以利用中间件强制追加Accept:application/json,使异常响应时都返回json。(参考教程L036.0中提到的方法)
创建中间件AcceptHeader
headers->set('Accept','application/json'); return$next($request); } }
在app/Http/Kernel.php中,将中间件加入路由组即可。
protected$middlewareGroups=[ 'web'=>[ . . . 'api'=>[ \App\Http\Middleware\AcceptHeader::class, 'throttle:60,1', 'bindings', ], ];
大功告成。
总结
到此这篇关于Laravel如何实现适合Api的异常处理响应格式的文章就介绍到这了,更多相关Laravel适合Api的异常处理响应格式内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。