Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 496|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-5-28 09:14:50 | 显示全部楼层 |阅读模式

    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
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-18 17:10 , Processed in 0.071070 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表