• flask异常处理:abort、errorhandler、app_errorhandler,封装全局异常处理


    1. abort()

    abort()函数也叫视图终止函数,用于提前退出一个请求,并用指定的错误码返回。既然是视图终止函数,就是说abort()函数是写在视图中的。那么这个函数就不能处理由于url不合法引起的异常,因为一旦url不合法,是无法进入到视图函数中的。

    flask-restful中的 abort() 的代码是封装的 flask 的 abort() 代码。

    flask abort() 源码:

    def abort(status, *args, **kwargs):
        return _aborter(status, *args, **kwargs)
    

    flask-restful 的 abort() 源码:

    def abort(http_status_code, **kwargs):
        try:
            original_flask_abort(http_status_code)
        except HTTPException as e:
            if len(kwargs):
                e.data = kwargs
            raise
    

    这里的 original_flask_abort() 即 flask 的 abort()。其实我们也可以自己来封装abort()这个函数,来实现我们需要的功能。

    1.1 使用方式一:传递一个错误码

    from flask import abort
    
    @app.route("/")
    def index():
        # abort函数可以提前终止视图函数
        abort(404)
    
        # 下面这条消息无法打印出来,因为上面abort函数已经终止了这个视图函数的运行。
        print("我还在运行ing")
        return "Index Page"
    
    

    参数http_status_code:传递状态码(错误码),必须是标准的http状态码。

    直接返回给前端页面一个对应错误码的错误信息。

    查看错误码:

    from werkzeug.exceptions import default_exceptions
    import pprint
    
    pprint.pprint(default_exceptions)
    

    结果:

    如果是以下列表之外的,会报服务器内部错误:{"message": "Internal Server Error"}
    可以看到2xx与3xx并不在此之列。

    
    {400: <class 'werkzeug.exceptions.BadRequest'>,
     401: <class 'werkzeug.exceptions.Unauthorized'>,
     403: <class 'werkzeug.exceptions.Forbidden'>,
     404: <class 'werkzeug.exceptions.NotFound'>,
     405: <class 'werkzeug.exceptions.MethodNotAllowed'>,
     406: <class 'werkzeug.exceptions.NotAcceptable'>,
     408: <class 'werkzeug.exceptions.RequestTimeout'>,
     409: <class 'werkzeug.exceptions.Conflict'>,
     410: <class 'werkzeug.exceptions.Gone'>,
     411: <class 'werkzeug.exceptions.LengthRequired'>,
     412: <class 'werkzeug.exceptions.PreconditionFailed'>,
     413: <class 'werkzeug.exceptions.RequestEntityTooLarge'>,
     414: <class 'werkzeug.exceptions.RequestURITooLarge'>,
     415: <class 'werkzeug.exceptions.UnsupportedMediaType'>,
     416: <class 'werkzeug.exceptions.RequestedRangeNotSatisfiable'>,
     417: <class 'werkzeug.exceptions.ExpectationFailed'>,
     418: <class 'werkzeug.exceptions.ImATeapot'>,
     422: <class 'werkzeug.exceptions.UnprocessableEntity'>,
     423: <class 'werkzeug.exceptions.Locked'>,
     428: <class 'werkzeug.exceptions.PreconditionRequired'>,
     429: <class 'werkzeug.exceptions.TooManyRequests'>,
     431: <class 'werkzeug.exceptions.RequestHeaderFieldsTooLarge'>,
     451: <class 'werkzeug.exceptions.UnavailableForLegalReasons'>,
     500: <class 'werkzeug.exceptions.InternalServerError'>,
     501: <class 'werkzeug.exceptions.NotImplemented'>,
     502: <class 'werkzeug.exceptions.BadGateway'>,
     503: <class 'werkzeug.exceptions.ServiceUnavailable'>,
     504: <class 'werkzeug.exceptions.GatewayTimeout'>,
     505: <class 'werkzeug.exceptions.HTTPVersionNotSupported'>}
    

    1.2 使用方式二:传递一个json格式字符串

    from flask import abort, jsonify
    
    @app.route("/")
    def index():
        code = 50000
        data = [{"data1": "lalallala", {"data2": "lolololo"}]
        json_data = jsonify({"code": code, "data": data})
        abort(json_data)
    
        # 下面这条消息无法打印出来,因为上面abort函数已经终止了这个视图函数的运行。
        print("我还在运行ing")
        return "Index Page"
    
    

    这种方法相当于 return ,直接把传入abort中的数据返回到前端。

    1.3 使用方式三:传递一个响应体

    from flask import abort, Response
    
    @app.route("/")
    def index():
        res = Response("Not Found", 404, {"name": "ttytty"})  # Response也可以返回响应体信息
        abort(res)
    
        # 下面这条消息无法打印出来,因为上面abort函数已经终止了这个视图函数的运行。
        print("我还在运行ing")
        return "Index Page"
    

    直接返回给前端这个响应体。方式二和方式三很相似。

    2. errorhandler

    捕捉当前app或蓝图的状态码,然后可以进行自定义处理。

    2.1 简单使用:

    from flask import jsonify
    from . import admin
    
    @admin.errorhandler(404)
    def error_404(error):
        """这个handler可以catch住所有abort(404)以及找不到对应router的处理请求"""
        response = dict(status=0, message="404 Not Found")
        return jsonify(response), 404
    
    @admin.errorhandler(Exception)
    def error_500(error):
        """这个handler可以catch住所有的abort(500)和raise exeception."""
        response = dict(status=0, message="500 Error")
        return jsonify(response), 400
    
    class MyError(Exception):
        """自定义错误类"""
        pass
    
    @admin.errorhandler(MyError)
    def MyErrorHandle(error):
        response = dict(status=0, message="400 Error")
        return jsonify(response), 400
    
    

    2.2 封装成全局异常捕获处理:

    1. 自定义异常类(有需要的话)
    
    from werkzeug.exceptions import HTTPException
    
    
    class EigenException(HTTPException):
        code = 500
        eigen_code = 4000
        description = 'Inner Server Error'
    
    
    class RequestError(EigenException):
        code = 400
    
    
    class DataNotFound(RequestError):
        code = 404
        eigen_code = 4004
        description = 'Data Not Found'
    
        def __init__(self, message):
            self.description = '%s Not Found' % message
    
    
    class InvalidRequest(RequestError):
        eigen_code = 4005
        description = 'Invalid Request URL'
    
    
    class MissingKey(RequestError):
        eigen_code = 4006
        description = 'Missing Key'
    
        def __init__(self, key):
            self.description = 'Missing Key `%s`' % key
    
    1. 捕获异常并处理:
    
    # 制定一个响应
    def json_response(code, error, status_code):
        response = make_response(json.dumps(dict(code=code, error=error)), status_code)
        response.headers['Content-Type'] = 'application/json; charset=utf-8'
        return response
    
    # 异常捕获处理
    @app.errorhandler(Exception)
    def handler_exception(e):
        if isinstance(e, 其他异常):
            code, status_code, error = 4000, 400, e.description
        elif isinstance(e, EigenException):
            code, status_code, error = e.eigen_code, e.code, e.description
        elif isinstance(e, HTTPException):
            code, status_code, error = e.code, e.code, e.description
        else:
            code, status_code, error = 5000, 500, '%s(%s)' % (e.__class__.__name__, str(e))
        return json_response(code, error, status_code)
    

    3. app_errorhandler

    捕捉全局状态码,并进行自定制异常处理

    在蓝本中编写错误处理程序有点不同,如果使用errorhandler修饰器,那么只有蓝本中的错误才会触发。如果想注册全局的错误处理程序,要用app_errorhandler。

    例如:

    
    from bookapp import bokkapp
    
    
    @bookapp.app_errorhandler(Exception)
    def handler_exception(e):
        if isinstance(e, 其他异常):
            code, status_code, error = 4000, 400, e.description
        elif isinstance(e, EigenException):
            code, status_code, error = e.eigen_code, e.code, e.description
        elif isinstance(e, HTTPException):
            code, status_code, error = e.code, e.code, e.description
        else:
            code, status_code, error = 5000, 500, '%s(%s)' % (e.__class__.__name__, str(e))
        response = dict(code=code, status=status_code, msg=error)
        return jsonify(response)
    

    **注意: **当我们不是使用的工厂模式创建app时,app.errorhandler(401),即可捕捉全局401状态;若使用了create_app方式创建app,则无法进行捕捉,若想捕捉,可以在蓝图中写,如admin.errorhandler(401),即捕捉admin蓝图下所有401状态码,admin.app_errorhandler(401),则是捕捉的全局的401状态码,即其他蓝图中的401状态,也会被捕捉,进行处理

    参考文章:

    1. https://www.cnblogs.com/huchong/p/9205651.html
    2. https://www.cnblogs.com/fiona-zhong/p/10218338.html
  • 相关阅读:
    django 单表操作
    爬虫学习
    DRF源码分析
    DRF权限和频率限制
    DRF版本和认证源码分析
    request高级部分
    多任务异步爬虫及selenium模块使用
    requests基本使用
    爬虫介绍及环境
    Flask生命周期的源码流程
  • 原文地址:https://www.cnblogs.com/ChangAn223/p/11323524.html
Copyright © 2020-2023  润新知