問題
公司需要將老專案遷移, 由於之前的錯誤返回都是不規範的, 對於錯誤處理都是直接返回 200 http code。大量的使用這樣的返回。
response()->json(200, ['msg'=>$msg])
已經沒有辦法更改了, 客戶端都是根據介面的的業務程式碼 code
來判斷的。但是在新的專案中嚴格規範使用異常丟擲, 但是異常丟擲後 http code 返回的是 500
。導致測試通過不了, 沒有辦法只能修改。
解決
使用了異常丟擲業務錯誤, 在 laravel
框架中, 異常都是統一處理的, 在 App\Exceptions\Handle
裡面進行了全域性處理。對於框架丟擲的異常, 全部由它來處理。但是當你想要在 Handle
裡面修改處理的時候, 你會發現並不會有任何效果。到底什麼原因導致的呢?
在入口檔案可以看到這麼一段程式碼
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
在這裡進行了全域性的異常服務註冊, 這裡先不關注異常在哪裡處理的。既然實際是沒有通過 Hanle 類處理, 猜測這裡服務可能被 Dingo 重新註冊過了。帶著這個想法可以看一下 Dingo 的服務註冊。在 Dingo\Api\Provider\DingoServiceProvider
看到了異常註冊
protected function registerExceptionHandler()
{
$this->app->singleton('api.exception', function ($app) {
return new ExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], $this->config('errorFormat'), $this->config('debug'));
});
}
這裡肯定會有疑問了, 這個單例模式也沒有重新註冊 Illuminate\Contracts\Debug\ExceptionHandler::class
這個類啊?沒錯, 因為 Dingo 接管了路由, 你實際使用的 \Dingo\Api\Routing\Router::class
, 所以 Dispatch 的會由 Dingo 來執行。這裡就不細說了。有興趣的可以看一下 Dingo 的處理。
Dispatch 處理可以在 Dingo\Api\Dispatcher
裡面找到。來看一下程式碼處理。
protected function dispatch(InternalRequest $request)
{
$this->routeStack[] = $this->router->getCurrentRoute();
$this->clearCachedFacadeInstance();
try {
$this->container->instance('request', $request);
$response = $this->router->dispatch($request);
if (! $response->isSuccessful() && ! $response->isRedirection()) {
throw new InternalHttpException($response);
} elseif (! $this->raw) {
$response = $response->getOriginalContent();
}
// 主要看這裡的 exception 處理 這裡就是接管的異常
} catch (HttpExceptionInterface $exception) {
$this->refreshRequestStack();
throw $exception;
}
$this->refreshRequestStack();
return $response;
}
先不用管這個介面類的異常, 來看看 Dingo 的 Handle 如何處理的。下面會提到處理為何這裡是介面, 還有該如何修改。
你需要從 render 方法來是查詢, 你最終會看到, 過程就不細講了。
protected function getExceptionStatusCode(Exception $exception, $defaultStatusCode = 500)
{
return ($exception instanceof HttpExceptionInterface) ? $exception->getStatusCode() : $defaultStatusCode;
}
這裡就和上面的介面類對應了, 為什麼返回 500 呢?看這段程式碼已經一目瞭然了。如果不是實現了 HttpExceptionInterface
的異常類, StatusCode
都是返回 500。所以需要做的就很簡單了, 實現 HttpExceptionInterface
就可以了。簡單實現:
class BaseException extends \Exception implements HttpExceptionInterface
{
public function getStatusCode()
{
return 200;
}
/**
* Returns response headers.
*
* @return array Response headers
*/
public function getHeaders()
{
return [];
}
這是一個 exception 基類, 需要的就是繼承就可以了。這樣就可以解決該問題了
本作品採用《CC 協議》,轉載必須註明作者和本文連結