Laravel如何實現(xiàn)適合Api的異常處理響應(yīng)格式
前言
Laravel全局捕獲異常后,會把異常轉(zhuǎn)為相應(yīng)的數(shù)據(jù)格式返回給用戶。如果想要規(guī)定的數(shù)據(jù)格式相應(yīng),那我們只需重寫異常捕獲后的處理方法即可。
異常處理流程
Illuminate\Foundation\Exception\Handler 中的 render 方法用來將異常轉(zhuǎn)化為響應(yīng)。
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() 中又調(diào)用了 prepareException() 對部分異常進行預(yù)處理,但并未執(zhí)行轉(zhuǎn)化為響應(yīng)的操作。
ModelNotFoundException 一般在模型查找不到拋出,prepareException() 中它被轉(zhuǎn)為 Symfony 包中NotFoundHttpException,默認狀態(tài)碼404;
AuthorizationException 在 Policy 權(quán)限未通過時拋出,prepareException() 中它被轉(zhuǎn)為 Symfony 包中 AccessDeniedHttpException,默認狀態(tài)碼403;
TokenMismatchException 在 CSRF 驗證未通過時拋出,prepareException() 中它被轉(zhuǎn)為 Symfony 包中 HttpException,給定狀態(tài)碼419;
其他異常直接返回。
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() ,預(yù)處理異常之后,又分別對 HttpResponseException、AuthenticationException 和 ValidationException 單獨處理,并轉(zhuǎn)為響應(yīng)返回。
除此以外的異常,都在 prepareJsonResponse() 或 prepareResponse() 處理 ,expectsJson() 用來判斷返回 json 響應(yīng)還是普通響應(yīng)。
修改異常響應(yīng)格式
了解了異常處理流程,接下來就處理異常響應(yīng)格式。
修改登錄認證異常格式
由上文可知,AuthenticationException 被捕獲后,調(diào)用 unauthenticated() 來處理。
protected function unauthenticated($request, AuthenticationException $exception) { return $request->expectsJson() ? response()->json(['message' => $exception->getMessage()], 401) : redirect()->guest($exception->redirectTo() ?? route('login')); }
在 appExceptionsHandler.php 中重寫 unauthenticated() 使其返回我們想要的數(shù)據(jù)格式。
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() 處理,進入此方法后我們需要繼續(xù)追蹤,若是需要 json 響應(yīng),最終交由 invalidJson() 處理。
protected function convertValidationExceptionToResponse(ValidationException $e, $request) { if ($e->response) { return $e->response; } return $request->expectsJson() ? $this->invalidJson($request, $e) : $this->invalid($request, $e); }
protected function invalidJson($request, ValidationException $exception) { return response()->json([ 'message' => $exception->getMessage(), 'errors' => $exception->errors(), ], $exception->status); }
我們繼續(xù)在 appExceptionsHandler.php 重寫 invalidJson() 即可自定義返回格式。
protected function invalidJson($request, ValidationException $exception) { return response()->json([ 'code' => 0, 'data' => $exception->errors(), ], $exception->status); }
修改其他異常格式
其他異常是調(diào)用 prepareJsonResponse() 來處理,此方法又調(diào)用 convertExceptionToArray() 來處理響應(yīng)格式。
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 ); }
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() 來自定義其他異常響應(yīng)格式。
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 響應(yīng)
代碼中多次出現(xiàn)了 expectsJson() ,此方法是用來判斷返回 json 響應(yīng)還是普通響應(yīng)。
public function expectsJson() { return ($this->ajax() && ! $this->pjax() && $this->acceptsAnyContentType()) || $this->wantsJson(); }
以下兩種條件下,會返回json響應(yīng)。
非XML請求、非pjax并且 Headers 中 Accept 設(shè)置為接收所有格式響應(yīng);
Headers Accept 設(shè)置為 /json、+json。如:Accept:application/json。
除此之外的情況,將不會響應(yīng)json。我們可以利用中間件強制追加 Accept:application/json,使異常響應(yīng)時都返回json。(參考教程 L03 6.0 中提到的方法)
創(chuàng)建中間件 AcceptHeader
<?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 中,將中間件加入路由組即可。
protected $middlewareGroups = [ 'web' => [ . . . 'api' => [ \App\Http\Middleware\AcceptHeader::class, 'throttle:60,1', 'bindings', ], ];
大功告成。
總結(jié)
到此這篇關(guān)于Laravel如何實現(xiàn)適合Api的異常處理響應(yīng)格式的文章就介紹到這了,更多相關(guān)Laravel適合Api的異常處理響應(yīng)格式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
php導(dǎo)出csv格式數(shù)據(jù)并將數(shù)字轉(zhuǎn)換成文本的思路以及代碼分享
最近接的一個項目,需要將一些統(tǒng)計結(jié)果之類的東西導(dǎo)出成CSV,以便做報表,根據(jù)往常經(jīng)驗,現(xiàn)將思路和代碼都發(fā)出來,如有更好的方法,希望高手指正2014-06-06CodeIgniter自定義控制器MY_Controller用法分析
這篇文章主要介紹了CodeIgniter自定義控制器MY_Controller用法,結(jié)合實例形式分析了CodeIgniter自定義控制器MY_Controller的定義與使用技巧,需要的朋友可以參考下2016-01-01yii框架builder、update、delete使用方法
這篇文章主要介紹了yii框架builder、update、delete使用方法,需要的朋友可以參考下2014-04-04微信公眾號支付之坑:調(diào)用支付jsapi缺少參數(shù) timeStamp等錯誤解決方法
這段時間一直比較忙,一忙起來真感覺自己就只是一臺掙錢的機器了(說的好像能掙到多少錢似的,呵呵);這會難得有點兒空閑時間,想把前段時間開發(fā)微信公眾號支付遇到問題及解決方法跟大家分享下,這些“暗坑”能不掉就不掉吧,要不然關(guān)鍵時刻出問題,真是讓人急的焦頭爛額2016-01-01PHP的Laravel框架結(jié)合MySQL與Redis數(shù)據(jù)庫的使用部署
這篇文章主要介紹了PHP的Laravel框架結(jié)合MySQL與Redis數(shù)據(jù)庫的使用部署,需要的朋友可以參考下2016-03-03CodeIgniter控制器之業(yè)務(wù)邏輯實例分析
這篇文章主要介紹了CodeIgniter控制器之業(yè)務(wù)邏輯使用方法,結(jié)合實例形式分析了業(yè)務(wù)邏輯所涉及的相關(guān)概念與具體使用方法,需要的朋友可以參考下2016-01-01