烧瓶自定义错误处理程序无法正确处理注册的错误类型

时间:2019-05-04 06:57:22

标签: python exception flask

我已经创建了一个基本的Flask应用程序,并为特定的自定义异常类型注册了一个自定义错误处理程序。但是,当抛出此异常类型并将其传递到堆栈上时,Flask将不使用指定的自定义错误处理程序。

我用基本的Exception类型创建了第二个错误处理程序,它成功捕获了错误。基本异常处理程序的存在不会影响自定义错误处理程序捕获错误的能力,如果不存在基本处理程序,则错误会一直持续到默认的Flask 500页面。

我也完成了print(srv.error_handler_spec),看来错误处理程序已成功注册。

这是srv.py的主要部分,这是我的Flask应用程序的入口点

from flask import Flask, request
from flask import jsonify

srv = Flask(__name__)

class APIError(Exception):
    def __init__(self, message, status_code=500):
        Exception.__init__(self)
        self.message = message
        self.status_code = status_code

    def log_error(self):
        logging.error(f"API error: {self.to_json()}")

    def to_dict(self):
        return {"message": self.message, "status_code": self.status_code}


@srv.errorhandler(Exception)
def exception_handler(e: Exception):
    response = jsonify(
        {"message": f"unhandled exception encountered", "status_code": 500}
    )
    logging.error(f"unhandled exception encountered. type: {e.__class__}")
    response.status_code = 500
    return response


@srv.errorhandler(APIError)
def api_error_handler(e: APIError):
    response = jsonify(e.to_dict())
    response.status_code = e.status_code
    return response


print(srv.error_handler_spec)


@srv.route("/", methods=["GET"])
def hello_world():
    return "hello world"


@srv.route("/error", methods=["GET"])
def error():
    raise APIError("generic error", status_code=400)

这是卷曲/error时Flask的日志输出

[32mapp_1      |[0m {None: {None: {<class 'Exception'>: <function exception_handler at 0x7f211b8a5598>, <class 'srv.APIError'>: <function api_error_handler at 0x7f211b8a5620>}}}
[32mapp_1      |[0m {None: {None: {<class 'Exception'>: <function exception_handler at 0x7f211b8a5e18>, <class '__main__.APIError'>: <function api_error_handler at 0x7f211b8a5ea0>}}}
[32mapp_1      |[0m  * Serving Flask app "srv" (lazy loading)
[32mapp_1      |[0m  * Environment: production
[32mapp_1      |[0m    WARNING: Do not use the development server in a production environment.
[32mapp_1      |[0m    Use a production WSGI server instead.
[32mapp_1      |[0m  * Debug mode: off
[32mapp_1      |[0m  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
[32mapp_1      |[0m ERROR:root:unhandled exception encountered. type: <class 'srv.APIError'>
[32mapp_1      |[0m 172.27.0.5 - - [04/May/2019 06:52:47] "POST /api/user/create HTTP/1.1" 500 -
[32mapp_1      |[0m INFO:werkzeug:172.27.0.5 - - [04/May/2019 06:52:47] "POST /api/user/create HTTP/1.1" 500 -
[32mapp_1      |[0m 172.27.0.5 - - [04/May/2019 06:52:47] "GET /error HTTP/1.1" 400 -
[32mapp_1      |[0m INFO:werkzeug:172.27.0.5 - - [04/May/2019 06:52:47] "GET /error HTTP/1.1" 400 -

从日志行ERROR:root:unhandled exception encountered. type: <class 'srv.APIError'>可以看到,它使用的是通用Exception处理程序,而不是APIError的自定义处理程序。

预期的行为是,Flask会改用自定义错误处理程序,而不打印任何日志行。

对于记录,curl的结果与返回响应的通用错误处理程序一致。通用处理程序破坏更具体的处理程序绝对不是问题。 (尽管根据Flask的文档,这也是错误的。)

有什么作用?

1 个答案:

答案 0 :(得分:0)

我找到了一种解决方法,即将APIError定义放入单独的Python文件并将其导入srv.py

失败的原因是因为isinstance()无法正常工作。引发的异常的类型为srv.APIError,但要检查的类型为__main__.APIError,它们不是同一类型。

这不是由于另一个模块的类型阴影,因为将错误类型名称更改为StupidError会得到相同的结果。

但是我仍然不知道为什么会首先发生这种情况。 :/