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

2025-05-27 0 25

前言

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

异常处理流程

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22
public function render($request, Exception $e)

{

if (method_exists($e, 'render') && $response = $e->render($request)) {

return Router::toResponse($request, $response);

} elseif ($e instanceof Responsable) {

return $e->toResponse($request);

}

$e = $this->prepareException($e);

if ($e instanceof HttpResponseException) {

return $e->getResponse();

} elseif ($e instanceof AuthenticationException) {

return $this->unauthenticated($request, $e);

} elseif ($e instanceof ValidationException) {

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;

其他异常直接返回。

?

1

2

3

4

5

6

7

8

9

10

11

12
protected function prepareException(Exception $e)

{

if ($e instanceof ModelNotFoundException) {

$e = new NotFoundHttpException($e->getMessage(), $e);

} elseif ($e instanceof AuthorizationException) {

$e = new AccessDeniedHttpException($e->getMessage(), $e);

} elseif ($e instanceof TokenMismatchException) {

$e = new HttpException(419, $e->getMessage(), $e);

}

return $e;

}

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

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

修改异常响应格式

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

修改登录认证异常格式

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

?

1

2

3

4

5

6
protected function unauthenticated($request, AuthenticationException $exception)

{

return $request->expectsJson()

? response()->json(['message' => $exception->getMessage()], 401)

: redirect()->guest($exception->redirectTo() ?? route('login'));

}

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

?

1

2

3

4

5

6

7

8

9
protected function unauthenticated($request, AuthenticationException $exception)

{

return $request->expectsJson()

? response()->json([

'code' => 0,

'data' => $exception->getMessage(),

], 401)

: redirect()->guest($exception->redirectTo() ?? route('login'));

}

修改验证异常格式

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

?

1

2

3

4

5

6

7

8

9

10
protected function convertValidationExceptionToResponse(ValidationException $e, $request)

{

if ($e->response) {

return $e->response;

}

return $request->expectsJson()

? $this->invalidJson($request, $e)

: $this->invalid($request, $e);

}

?

1

2

3

4

5

6

7
protected function invalidJson($request, ValidationException $exception)

{

return response()->json([

'message' => $exception->getMessage(),

'errors' => $exception->errors(),

], $exception->status);

}

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

?

1

2

3

4

5

6

7
protected function invalidJson($request, ValidationException $exception)

{

return response()->json([

'code' => 0,

'data' => $exception->errors(),

], $exception->status);

}

修改其他异常格式

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

?

1

2

3

4

5

6

7

8

9
protected function prepareJsonResponse($request, Exception $e)

{

return new JsonResponse(

$this->convertExceptionToArray($e),

$this->isHttpException($e) ? $e->getStatusCode() : 500,

$this->isHttpException($e) ? $e->getHeaders() : [],

JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES

);

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14
protected function convertExceptionToArray(Exception $e)

{

return config('app.debug') ? [

'message' => $e->getMessage(),

'exception' => get_class($e),

'file' => $e->getFile(),

'line' => $e->getLine(),

'trace' => collect($e->getTrace())->map(function ($trace) {

return Arr::except($trace, ['args']);

})->all(),

] : [

'message' => $this->isHttpException($e) ? $e->getMessage() : 'Server Error',

];

}

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16
protected function convertExceptionToArray(Exception $e)

{

return config('app.debug') ? [

'code' => 0,

'data' => $e->getMessage(),

'exception' => get_class($e),

'file' => $e->getFile(),

'line' => $e->getLine(),

'trace' => collect($e->getTrace())->map(function ($trace) {

return Arr::except($trace, ['args']);

})->all(),

] : [

'code' => 0,

'data' => $this->isHttpException($e) ? $e->getMessage() : 'Server Error',

];

}

强制 json 响应

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

?

1

2

3

4
public function expectsJson()

{

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

2

3

4

5

6

7

8

9

10

11

12

13

14

15
<?php

namespace App\\Http\\Middleware;

use Closure;

class AcceptHeader

{

public function handle($request, Closure $next)

{

$request->headers->set('Accept', 'application/json');

return $next($request);

}

}

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

?

1

2

3

4

5

6

7

8

9

10

11
protected $middlewareGroups = [

'web' => [

.

.

.

'api' => [

\\App\\Http\\Middleware\\AcceptHeader::class,

'throttle:60,1',

'bindings',

],

];

大功告成。

总结

到此这篇关于Laravel如何实现适合Api的异常处理响应格式的文章就介绍到这了,更多相关Laravel适合Api的异常处理响应格式内容请搜索快网idc以前的文章或继续浏览下面的相关文章希望大家以后多多支持快网idc!

原文链接:https://segmentfault.com/a/1190000022916150

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Laravel如何实现适合Api的异常处理响应格式 https://www.kuaiidc.com/70690.html

相关文章

发表评论
暂无评论