flask 重寫HTTPException類並自定義異常信息


前言

flask默認返回的異常是html格式的頁面,但為了能更好的支持json的返回,所以我們得重寫異常類的返回。
自定義返回符合resful風格的json,是重寫了werkzeug.exceptions中的HTTPException異常類。

源碼

在HTTPException類下第147-165行,是整個異常信息的返回格式,我們可以看得返回的類型是text/html
具體的返回值是在get_body方法中實現,所以我們需要重寫兩個函數方法,get_body和get_headers。

代碼

目錄結構

首先我們在項目的目錄下新建一個libs目錄,新建兩個py文件,error.py和errorcode.py。

error.py文件是重寫異常類的方法

首先我們得先繼承HTTPException類作為父類

from werkzeug.exceptions import HTTPException



class APIException(HTTPException):
    """
    為了使代碼簡潔, 首先定義一個最基本的類, 供其它類繼承, 這個自定義的APIException繼承HTTPException.
    1. 為了返回特定的body信息, 需要重寫get_body;
    2. 為了指定返回類型, 需要重寫get_headers.
    3. 為了接收自定義的參數, 重寫了__init__;
    4. 同時定義了類變量作為幾個默認參數.(code500和error_code:999 均表示未知錯誤, error_code表示自定義異常code)
    """
    code = 500
    msg = 'sorry,internal error'
    error_code = 999
    data = ''
    
    # 自定義需要返回的信息,在初始化完成並交給父類
    def __init__(self, msg=None, code=None, error_code=None, data=None):
        if code:
            self.code = code
        if msg:
            self.msg = msg
        if error_code:
            self.error_code = error_code
        if data:
            self.data = data
        super(APIException, self).__init__(msg, None)

前面我們已經定義好了默認的錯誤響應碼和返回消息,現在我們重寫get_body和get_headers方法

    def get_body(self, environ=None):
        body = dict(
            error_code=self.error_code,
            msg=self.msg,
            request=request.method + ' ' + self.get_url_no_parm(),
            data=self.data
        )
        # sort_keys 取消排序規則,ensure_ascii 中文顯示
        text = json.dumps(body, sort_keys=False, ensure_ascii=False)
        return text

    def get_headers(self, environ=None):
        return [('Content-Type', 'application/json')]

上面用到的self.get_url_no_parm方法是為了更好的知道我們訪問出錯的視圖,我們從請求上下文中獲取到路徑展示。

from flask import request

def get_url_no_parm():
    full_path = str(request.path)
    return full_path

下面是整個APIException的完整代碼

import json

from flask import request
from werkzeug.exceptions import HTTPException



class APIException(HTTPException):
    """
    為了使代碼簡潔, 首先定義一個最基本的類, 供其它類繼承, 這個自定義的APIException繼承HTTPException.
    1. 為了返回特定的body信息, 需要重寫get_body;
    2. 為了指定返回類型, 需要重寫get_headers.
    3. 為了接收自定義的參數, 重寫了__init__;
    4. 同時定義了類變量作為幾個默認參數.(code500和error_code:999 均表示未知錯誤, error_code表示自定義異常code)
    """
    code = 500
    msg = 'sorry,internal error'
    error_code = 999
    data = ''

    # 自定義需要返回的信息,在初始化完成並交給父類
    def __init__(self, msg=None, code=None, error_code=None, data=None):
        if code:
            self.code = code
        if msg:
            self.msg = msg
        if error_code:
            self.error_code = error_code
        if data:
            self.data = data
        super(APIException, self).__init__(msg, None)

    def get_body(self, environ=None):
        body = dict(
            error_code=self.error_code,
            msg=self.msg,
            request=request.method + ' ' + self.get_url_no_parm(),
            data=self.data
        )
        # sort_keys 取消排序規則,ensure_ascii 中文顯示
        text = json.dumps(body, sort_keys=False, ensure_ascii=False)
        return text

    def get_headers(self, environ=None):
        return [('Content-Type', 'application/json')]

    @staticmethod
    def get_url_no_parm():
        full_path = str(request.path)
        return full_path


errorcode.py

我們定義的錯誤狀態碼,繼承我們的APIException類,我們自定義的error_code表示的含義最好用文本形式記錄下來,方面后期排錯查看。

class ServerError(APIException):
    code = 500
    msg = "server is invallid"
    error_code = 999
    data = ''


class ClientTypeError(APIException):
    code = 400
    msg = "client is invallid"
    error_code = 1006
    data = ''


class ParameterException(APIException):
    code = 400
    msg = 'invalid parameter'
    error_code = 1000
    data = ''


class AuthFailed(APIException):
    code = 401
    msg = 'invalid parameter'
    error_code = 1001
    data = ''


class ValError(APIException):
    code = 404
    msg = 'invalid parameter'
    error_code = 1001
    data = ''

全局異常捕獲

雖然我們前面定義好了自定義的異常類,但不知道應該如何讓flask捕獲到異常后,拋出我們自定義的異常信息。
flask內置好了一個裝飾器方法,用於我們捕獲異常並處理異常的方法app.errorhandler
這是程序上下文中的一個方法,所以我們需要放在app初始化后執行,在這里我們放到manage.py這個啟動入口下。

······
# 創建flask應用對象
app = create_app('develop')
······

@app.errorhandler(Exception)
def framework_error(e):
    # 判斷異常是不是APIException
    if isinstance(e, APIException):
        return e
    # 判斷異常是不是HTTPException
    if isinstance(e, HTTPException):
        log.error(e)
        code = e.code
        # 獲取具體的響應錯誤信息
        msg = e.description
        error_code = 1007
        return APIException(code=code, msg=msg, error_code=error_code)
    # 異常肯定是Exception
    else:
        # 如果是調試模式,則返回e的具體異常信息。否則返回json格式的ServerException對象!
        # 針對於異常信息,我們最好用日志的方式記錄下來。
        if app.config["DEBUG"]:
            log.error(e)
            return e
        else:
            log.error(e)
            return ServerError()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM