zoukankan      html  css  js  c++  java
  • 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()
    
  • 相关阅读:
    更新github上的代码
    使用git上传项目代码到github
    解决jenkins插件列表为空的问题
    P3200 [HNOI2009]有趣的数列
    BZOJ3907 网格
    解决SDK下载时速度过慢的问题
    实用的Android代码片段集合(精)
    广播与服务(二)
    action使用大全
    广播与服务(一)
  • 原文地址:https://www.cnblogs.com/se7enjean/p/12955417.html
Copyright © 2011-2022 走看看