yii2 開發 api 接口時優雅的處理全局異常

前言:我的以爲,學習或溫習一套Web框架,在快速閱讀一遍文檔後,應從路由,控制器,請求/響應對象,數據模型(Logic,Dao,Entity),全局異常處理幾個方面下手,這幾項瞭解後,框架上手就遊刃有餘了。而後我比較喜歡在開工前整理好框架的全局異常處理,方便寫 api時錯誤的統一響應。php


api接口的開發過程當中,咱們須要對用戶數據進行嚴格的校驗,防止非法輸入對服務產生安全問題,在開發過程當中,我比較喜歡即時的以拋出異常的方式中斷請求的處理,並以全局異常處理器格式化處理後統一返回給客戶端。html

今天就把 yii2 自帶的全局異常處理器改寫至對 api 友好(yii2yii\web\HttpException默認對 web 請求友好,都是以text/html的方式返回錯誤描述,對api不友好,api固然是json)。web

註冊異常處理器

yii2也是以 controller/action 的方式定義一個異常處理器的,咱們能夠在 components=>errorHandler中自定義。json

# config/web.php
'components' => [
    'errorHandler' => [
        'errorAction' => 'exception/handler'
    ]
]

異常處理器

定義相應的異常處理器,app\actions\ErrorApiAction 繼承 yii\web\ErrorAction,能夠拿到yii2爲咱們整理好的全局異常。api

# controllers/ExceptionController.php
<?php

namespace app\controllers;

use yii\web\Controller;

class ExceptionController extends Controller
{
    /**
     * 爲 actionHandler 掛載獨立的 action
     * @return array
     */
    public function actions()
    {
        return [
            'handler' => [
                'class' => 'app\actions\ErrorApiAction',
            ]
        ];
    }
}

api友好的錯誤異常處理器,這裏我也只是簡單的把響應格式改了一下,異常的上下文仍是用yii2自帶的處理的。安全

#actions/ErrorApiAction.php
<?php
/**
 * @author wangzhijian@styd.com
 * @date 2019-5-13 17:20:10
 * Api 全局錯誤異常處理器
 */

namespace app\actions;

use Yii;
use yii\web\ErrorAction;
use yii\web\Response;

class ErrorApiAction extends ErrorAction
{
    public function run()
    {
        // 根據異常類型設定相應的響應碼
        Yii::$app->getResponse()->setStatusCodeByException($this->exception);
        // json 格式返回
        Yii::$app->getResponse()->format = Response::FORMAT_JSON;
        // 返回的內容數據
        return [
            'msg' => $this->exception->getMessage(),
            'err' => $this->exception->getCode()
        ];
    }
}

異常實體

主要是簡單的把狀態碼的傳遞封裝一下,用更容易理解的類名來代理傳遞。
exceptions/HttpException.phpyii2

<?php
/**
 * app 異常基礎類
 */

namespace app\exceptions;

class HttpException extends \yii\web\HttpException
{
    public function __construct($message = null, $code = 0, \Exception $previous = null)
    {
        parent::__construct($this->statusCode, $message, $code, $previous);
    }
}

exceptions/HttpForbiddenException.phpapp

<?php
/**
 * 400 bad request
 */

namespace app\exceptions;

class HttpBadRequestException extends HttpException
{
    public $statusCode = 400;
}

exceptions/HttpUnauthorizedException.php框架

<?php
/**
 * 401 unauthorized
 */

namespace app\exceptions;

class HttpUnauthorizedException extends HttpException
{
    public $statusCode = 401;
}

exceptions/HttpForbiddenException.phpyii

<?php
/**
 * 403 forbidden
 */

namespace app\exceptions;

class HttpForbiddenException extends HttpException
{
    public $statusCode = 403;
}

exceptions/HttpNotFoundException.php

<?php
/**
 * 404 not found
 */

namespace app\exceptions;

class HttpNotFoundException extends HttpException
{
    public $statusCode = 404;
}

使用範例

在一些 service logic model 中根據須要即時拋出異常便可,上層控制器拿到的永遠都是正常的返回數據,絕對的2xx響應簇

throw new HttpBadRequestException("具體的非法描述", 4001);
throw new HttpUnauthorizedException("請認證後訪問");
throw new HttpForbiddenException("無權訪問");
throw new HttpNotFoundException("請求資源不存在");

clipboard.png

2019-5-16 今天發現 yii2 自帶了一些 http 的異常類,是我沒仔細看源碼....

yii\web\BadRequestHttpException
yii\web\ConflictHttpException
yii\web\ForbiddenHttpException
yii\web\GoneHttpException
yii\web\MethodNotAllowedHttpException
yii\web\NotAcceptableHttpException
yii\web\NotFoundHttpException
yii\web\RangeNotSatisfiableHttpException
yii\web\ServerErrorHttpException
yii\web\TooManyRequestsHttpException
yii\web\UnauthorizedHttpException
yii\web\UnprocessableEntityHttpException
yii\web\UnsupportedMediaTypeHttpException
相關文章
相關標籤/搜索