当前位置:首页 > CMS教程 > 其它CMS > 列表

Laravel如何实现适合Api的异常处理响应格式

发布:smiling 来源: PHP粉丝网  添加日期:2022-03-14 15:29:24 浏览: 评论:0 

这篇文章主要给大家介绍了关于Laravel如何实现适合Api的异常处理响应格式的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Laravel具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

Laravel全局捕获异常后,会把异常转为相应的数据格式返回给用户,如果想要规定的数据格式相应,那我们只需重写异常捕获后的处理方法即可。

异常处理流程

Illuminate\Foundation\Exception\Handler 中的 render 方法用来将异常转化为响应。

  1. public function render($request, Exception $e
  2.  if (method_exists($e'render') && $response = $e->render($request)) { 
  3.  return Router::toResponse($request$response); 
  4.  } elseif ($e instanceof Responsable) { 
  5.  return $e->toResponse($request); 
  6.  } 
  7.  
  8.  $e = $this->prepareException($e); 
  9.  
  10.  if ($e instanceof HttpResponseException) { 
  11.  return $e->getResponse(); 
  12.  } elseif ($e instanceof AuthenticationException) { 
  13.  return $this->unauthenticated($request$e); 
  14.  } elseif ($e instanceof ValidationException) { 
  15.  return $this->convertValidationExceptionToResponse($e$request); 
  16.  } 
  17.  
  18.  return $request->expectsJson() 
  19.    ? $this->prepareJsonResponse($request$e
  20.    : $this->prepareResponse($request$e); 

render() 中又调用了 prepareException() 对部分异常进行预处理,但并未执行转化为响应的操作。

ModelNotFoundException 一般在模型查找不到抛出,prepareException() 中它被转为 Symfony 包中NotFoundHttpException,默认状态码404;

AuthorizationException 在 Policy 权限未通过时抛出,prepareException() 中它被转为 Symfony 包中 AccessDeniedHttpException,默认状态码403;

TokenMismatchException 在 CSRF 验证未通过时抛出,prepareException() 中它被转为 Symfony 包中 HttpException,给定状态码419;

其他异常直接返回。

  1. protected function prepareException(Exception $e
  2.  if ($e instanceof ModelNotFoundException) { 
  3.  $e = new NotFoundHttpException($e->getMessage(), $e); 
  4.  } elseif ($e instanceof AuthorizationException) { 
  5.  $e = new AccessDeniedHttpException($e->getMessage(), $e); 
  6.  } elseif ($e instanceof TokenMismatchException) { 
  7.  $e = new HttpException(419, $e->getMessage(), $e); 
  8.  } 
  9.  
  10.  return $e

在回到 render() ,预处理异常之后,又分别对 HttpResponseException、AuthenticationException 和 ValidationException 单独处理,并转为响应返回。

除此以外的异常,都在 prepareJsonResponse() 或 prepareResponse() 处理 ,expectsJson() 用来判断返回 json 响应还是普通响应。

修改异常响应格式

了解了异常处理流程,接下来就处理异常响应格式。

修改登录认证异常格式

由上文可知,AuthenticationException 被捕获后,调用 unauthenticated() 来处理。

  1. protected function unauthenticated($request, AuthenticationException $exception
  2.  return $request->expectsJson() 
  3.     ? response()->json(['message' => $exception->getMessage()], 401) 
  4.     : redirect()->guest($exception->redirectTo() ?? route('login')); 

在 appExceptionsHandler.php 中重写 unauthenticated() 使其返回我们想要的数据格式。

  1. protected function unauthenticated($request, AuthenticationException $exception
  2.  return $request->expectsJson() 
  3.   ? response()->json([ 
  4.    'code' => 0, 
  5.    'data' => $exception->getMessage(), 
  6.   ], 401) 
  7.   : redirect()->guest($exception->redirectTo() ?? route('login')); 

修改验证异常格式

同样由上文可知,ValidationException 被捕获后交由 convertValidationExceptionToResponse() 处理,进入此方法后我们需要继续追踪,若是需要 json 响应,最终交由 invalidJson() 处理。

  1. protected function convertValidationExceptionToResponse(ValidationException $e$request
  2.  if ($e->response) { 
  3.   return $e->response; 
  4.  } 
  5.  
  6.  return $request->expectsJson() 
  7.     ? $this->invalidJson($request$e
  8.     : $this->invalid($request$e); 
  9.  
  10. protected function invalidJson($request, ValidationException $exception
  11.  return response()->json([ 
  12.   'message' => $exception->getMessage(), 
  13.   'errors' => $exception->errors(), 
  14.  ], $exception->status); 

我们继续在 appExceptionsHandler.php 重写 invalidJson() 即可自定义返回格式。

  1. protected function invalidJson($request, ValidationException $exception
  2.  return response()->json([ 
  3.   'code' => 0, 
  4.   'data' => $exception->errors(), 
  5.  ], $exception->status); 

修改其他异常格式

其他异常是调用 prepareJsonResponse() 来处理,此方法又调用 convertExceptionToArray() 来处理响应格式。

  1. protected function prepareJsonResponse($request, Exception $e
  2.  return new JsonResponse( 
  3.   $this->convertExceptionToArray($e), 
  4.   $this->isHttpException($e) ? $e->getStatusCode() : 500, 
  5.   $this->isHttpException($e) ? $e->getHeaders() : [], 
  6.   JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES 
  7.  ); 
  8.  
  9. protected function convertExceptionToArray(Exception $e
  10.  return config('app.debug') ? [ 
  11.   'message' => $e->getMessage(), 
  12.   'exception' => get_class($e), 
  13.   'file' => $e->getFile(), 
  14.   'line' => $e->getLine(), 
  15.   'trace' => collect($e->getTrace())->map(function ($trace) { 
  16.    return Arr::except($trace, ['args']); 
  17.   })->all(), 
  18.  ] : [ 
  19.   'message' => $this->isHttpException($e) ? $e->getMessage() : 'Server Error'
  20.  ]; 

在 appExceptionsHandler.php 中重写 convertExceptionToArray() 来自定义其他异常响应格式。

  1. protected function convertExceptionToArray(Exception $e
  2.  return config('app.debug') ? [ 
  3.   'code' => 0, 
  4.   'data' => $e->getMessage(), 
  5.   'exception' => get_class($e), 
  6.   'file' => $e->getFile(), 
  7.   'line' => $e->getLine(), 
  8.   'trace' => collect($e->getTrace())->map(function ($trace) { 
  9.    return Arr::except($trace, ['args']); 
  10.   })->all(), 
  11.  ] : [ 
  12.   'code' => 0, 
  13.   'data' => $this->isHttpException($e) ? $e->getMessage() : 'Server Error'
  14.  ]; 

强制 json 响应

代码中多次出现了 expectsJson() ,此方法是用来判断返回 json 响应还是普通响应。

  1. public function expectsJson() 
  2.  return ($this->ajax() && ! $this->pjax() && $this->acceptsAnyContentType()) || $this->wantsJson(); 

以下两种条件下,会返回json响应。

非XML请求、非pjax并且 Headers 中 Accept 设置为接收所有格式响应;

Headers Accept 设置为 /json、+json。如:Accept:application/json。

除此之外的情况,将不会响应json。我们可以利用中间件强制追加 Accept:application/json,使异常响应时都返回json,(参考教程 L03 6.0 中提到的方法)

创建中间件 AcceptHeader

  1. <?php 
  2.  
  3. namespace App\Http\Middleware; 
  4.  
  5. use Closure; 
  6.  
  7. class AcceptHeader 
  8.  public function handle($request, Closure $next
  9.  { 
  10.   $request->headers->set('Accept''application/json'); 
  11.  
  12.   return $next($request); 
  13.  } 

在 app/Http/Kernel.php 中,将中间件加入路由组即可。

  1. protected $middlewareGroups = [ 
  2.  'web' => [ 
  3.   . 
  4.   . 
  5.   . 
  6.  'api' => [ 
  7.   \App\Http\Middleware\AcceptHeader::class
  8.   'throttle:60,1'
  9.   'bindings'
  10.  ], 
  11. ]; 

大功告成。

Tags: Laravel异常处理响应 Api

分享到: