当前位置: 首页 > 后端技术 > PHP

Laravel创建了适合Api的异常处理响应格式

时间:2023-03-30 00:24:42 PHP

Laravel在全局捕获到异常后,会将异常转换成对应的数据格式返回给用户。如果我们要匹配指定的数据格式,那么只需要在捕获到异常后重写处理方法即可。Illuminate\Foundation\Exception\Handler中的render方法用于将异常转化为响应。publicfunctionrender($request,Exception$e){if(method_exists($e,'render')&&$response=$e->render($request)){返回Router::toResponse($request,$response);}elseif($einstanceofResponsable){return$e->toResponse($request);$e=$this->prepareException($e);如果($einstanceofHttpResponseException){返回$e->getResponse();}elseif($einstanceofAuthenticationException){return$this->unauthenticated($request,$e);}elseif($einstanceofValidationException){return$this->convertValidationExceptionToResponse($e,$request);返回$request->expectsJson()?$this->prepareJsonResponse($request,$e):$this->prepareResponse($request,$e);}render()调用prepareException()准备处理一些异常,但没有执行转成的动作一个回应。当找不到模型时,通常会抛出ModelNotFoundException。在prepareException()中转换为Symfony包中的NotFoundHttpException,默认状态码为404。Policy权限失败时抛出AuthorizationException。在prepareException()中,它被转换为Symfony包中的AccessDeniedHttpException,默认状态码为403;CSRF验证失败时抛出TokenMismatchException,在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){返回$request->expectsJson()?response()->json(['message'=>$exception->getMessage()],401):redirect()->guest($exception->redirectTo()??route('login'));}重写appExceptionsHandler.php中的unauthenticated()返回我们想要的数据格式。protectedfunctionunauthenticated($request,AuthenticationException$exception){返回$request->expectsJson()?response()->json(['code'=>0,'data'=>$exception->getMessage(),],401):redirect()->guest($exception->redirectTo()??路由('login'));}修改校验异常格式从上面也可以看出,捕获到ValidationException后,会由convertValidationExceptionToResponse()处理。进入这个方法后,我们需要继续跟踪。如果需要json响应,它将由invalidJson()处理。受保护的函数convertValidationExceptionToResponse(ValidationException$e,$request){if($e->response){return$e->response;返回$request->expectsJson()?$this->invalidJson($request,$e):$this->invalid($request,$e);}保护函数invalidJson($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()来处理的,prepareJsonResponse()又调用convertExceptionToArray()来处理响应格式。受保护的函数prepareJsonResponse($request,Exception$e){返回新的JsonResponse($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')?['消息'=>$e->getMessage(),'异常'=>get_class($e),'文件'=>$e->getFile(),'line'=>$e->getLine(),'trace'=>collect($e->getTrace())->map(function($trace){returnArr::except($trace,['args']);})->all(),]:['消息'=>$this->isHttpException($e)?$e->getMessage():'ServerError',];}在appExceptionsHandler.php中重写convertExceptionToArray()来自定义其他异常响应格式。受保护的函数convertExceptionToArray(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响应。Non-XMLrequest,non-pjaxandAcceptinHeaders设置为接收所有格式响应;HeadersAccept设置为/json,+json。如:接受:application/json。其他情况下,不会响应json。我们可以使用中间件强制添加Accept:application/json,这样响应异常时返回json。(参考教程L036.0中提到的方法)创建中间件AcceptHeaderheaders->set('接受','应用程序/json');返回$next($request);}}在app/Http/Kernel.php中,将中间件添加到路由组即可。受保护的$middlewareGroups=['web'=>[...'api'=>[\App\Http\Middleware\AcceptHeader::class,'throttle:60,1','bindings',],];你完成了。