1. 程式人生 > >laravel-異常處理

laravel-異常處理

laravel 異常丟擲

在開發中錯誤處理是非常重要的,最重要是兩點:第一,宣告異常的錯誤程式碼和資訊。第二,不同場景下丟擲異常的有所不同,比如 api 中一般是前端 ajax 請求,那麼丟擲的異常應該是 json 形式,如果是開發模式下,頁面中丟擲普通異常,便於程式猿調錯,在生產環境下,則統一將錯誤彙總放入一個錯誤頁面進行渲染。

宣告異常

就以一個使用者模組來舉例:

在 /config/exceptions.php 中宣告丟擲異常的資訊和錯誤程式碼

<?php
return [
    'not_found_api' => ['message' => '介面未找到'
, 'code' => '404'], 'not_found_page' => ['message' => '頁面未找到', 'code' => '404'], 'user' => [ 'already_logout' => ['message' => '您已處於登出狀態,請重新登入', 'code' => '40005'], 'permission_deny' => ['message' => '您無訪問許可權', 'code' => '40001'], 'captcha_error'
=> ['message' => '簡訊驗證碼錯誤', 'code' => '40002'], 'not_found' => ['message' => '該使用者不存在', 'code' => '40003'], 'not_admin' => ['message' => '該賬號沒有管理後臺許可權!', 'code' => '40004'], ] ];

在 /app/Exceptions/ 下的檔案目錄結構:
app/Exceptions
      BaseException.php
      User.php
      Handler.php

BaseException.php : 接受和處理異常,並傳入父類的建構函式異常處理中

<?php

namespace App\Exceptions;

use JsonSerializable;
use Exception;

class BaseException extends Exception implements JsonSerializable{

    const EXCEPTION_CONFIG_PREFIX = 'exceptions.';

    public function __construct($config = '', $message = null, $code = null){
        $exception = config(static::EXCEPTION_CONFIG_PREFIX.$config);
        $code  = is_null($code)? $exception['code'] : $code;
        $message = is_null($message) ? $exception['message'] : $message;
        parent::__construct($message, $code);
    }

    public function jsonSerialize(){
        return [
            'errCode' => $this->getCode(),
            'message' => $this->getMessage()
        ];
    }

    public function setMessage($message){
        $this->message = $message;
    }

    public function setCode($code){
        $this->code = $code;
    }
}

User.php : 宣告使用者 User 模組中的異常

<?php

namespace App\Exceptions;

class User extends BaseException{
    const EXCEPTION_CONFIG_PREFIX = 'exceptions.user.';
}

Handler.php : 處理異常

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
//區別是否 ajax 請求 api 而分別處理的 404 錯誤
use App\Exceptions\NotFoundApi as NotFoundApiException;
use App\Exceptions\NotFoundPage as NotFoundPageException;
//在此名稱空間 /vendor/symfony/http-kernel/Exception 下有許多異常,可以參考一下
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

use App\Traits\Response as ResponseTrait;

class Handler extends ExceptionHandler
{
    use ResponseTrait;

    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        HttpException::class,
        ModelNotFoundException::class,
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception  $e
     * @return void
     */
    public function report(Exception $e)
    {
        return parent::report($e);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {
        //如果是生產環境
        if (env('APP_DEGUB')) {
            $exceptions = [];
            $exceptions['code'] = $e->getCode();
            $exceptions['message'] = $e->getMessage();
            //上線時,需要對丟擲的異常進行彙總互動至前端 view 中
            return response()->view("errors.exceptions", ['exceptions' => $exceptions]);
        }
        if ($e instanceof ModelNotFoundException) {
            $e = new NotFoundHttpException($e->getMessage(), $e);
        }

        /**
         * 除錯環境下,不需要返回json格式的結果
         */
        if(!env('APP_NEED_JSON_RESPONSE')){
            return parent::render($request, $e);
        }

        if($request->ajax() || $request->wantsJson()){
            if($e instanceof NotFoundHttpException){
                $e = new NotFoundApiException;
            }

            return $this->jsonResponse(null, $e->getMessage(), $e->getCode());
        }else{
            if($e instanceof NotFoundHttpException){
                $e = new NotFoundPageException;
            }

            return parent::render($request, $e);
        }
    }
}

準備工作都做好後,拋異常就非常簡單了 :

use App\Exceptions\User as UserException;

throw new UserException('captcha_error');