【问题标题】:Catching custom exceptions raised in Flask API. All exceptions raised end up in 500 Error [duplicate]捕获 Flask API 中引发的自定义异常。引发的所有异常最终都会出现 500 错误 [重复]
【发布时间】:2018-10-16 11:49:14
【问题描述】:

我希望能够在我的 API 中引发验证和其他异常,并在将错误消息作为 JSON 返回的包装视图中捕获它们。

我想我可以使用这样的东西:

异常

class APIException(Exception):

    def __init__(self, message, status_code=406):
        super().__init__(message)
        self.status_code = status_code

捕获异常

# Todo: find a better way of handling this. Flask should have some way of handling exceptions better than this
def catch_errors(view):
    @functools.wraps(view)
    def wrapped_view(**kwargs):
        try:
            return view(**kwargs)
        except APIException as e:
            # It seems to hit here
            return json_response({'message': str(e)}, e.status_code) 
        except Exception as e:
            # But bubbles up to here and returns this
            return json_response({'message': str(e)}, 500)

    return wrapped_view

路线

@router.route('/a-route', methods=['POST'])
@catch_errors
def get():
    return json_response(ARouteAPI().post(request.get_json()))

API 处理后

class ARouteAPI():

    def post(data):
        if not data.something:
            raise APIException("Invalid data error")

我遇到的问题是,无论我抛出什么异常,它都会冒泡到完整的Exception 并命中500,因此它永远不会返回APIException。

有人知道为什么吗?如何解决?

或者有没有更好的方法来处理这个问题?

更新

仍然为此做噩梦。

按照@Hyunwoo 的建议,更好的处理方法是使用@app.errorhandler 装饰器(在我的例子中,@router 是我的蓝图名称,所以我使用@router.errorhandler)。

但是,无论抛出什么异常,它最终都会遇到 500 错误,我不知道为什么。

我发现了类似的例子,其中调试模式会导致问题再次出现,我认为这可能会导致问题,但我已将调试模式设置为 false

错误处理程序

router = Blueprint('router', __name__)


@router.errorhandler(APIException)
def api_exception_handler(e):
    return jsonify({'message': str(e)}, e.status_code), 400

@router.errorhandler(500)
def error_handler(e):
    return jsonify({'message': str(e)}), 500 # Always hits this whatever exception is raised

堆栈跟踪

[2018-10-16 23:48:39,767] ERROR in app: Exception on /drone/7 [PUT]
Traceback (most recent call last):
  File "/home/sarcoma/PycharmProjects/drone_squadron/venv/lib/python3.5/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/sarcoma/PycharmProjects/drone_squadron/venv/lib/python3.5/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/sarcoma/PycharmProjects/drone_squadron/venv/lib/python3.5/site-packages/flask_cors/extension.py", line 161, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/home/sarcoma/PycharmProjects/drone_squadron/venv/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/sarcoma/PycharmProjects/drone_squadron/venv/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/sarcoma/PycharmProjects/drone_squadron/venv/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/sarcoma/PycharmProjects/drone_squadron/venv/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/sarcoma/PycharmProjects/drone_squadron/drone_squadron/router.py", line 62, in wrapped_view
    return view(**kwargs)
  File "/home/sarcoma/PycharmProjects/drone_squadron/drone_squadron/router.py", line 159, in drone_detail
    return JsonRequestHandler.detail(DroneApi(), item_id)
  File "/home/sarcoma/PycharmProjects/drone_squadron/drone_squadron/request/json_request_handler.py", line 39, in detail
    return json_response(api.put(item_id, request.get_json()))
  File "/home/sarcoma/PycharmProjects/drone_squadron/drone_squadron/api/drone_api.py", line 42, in put
    raise APIException("Not enough scrap")
drone_squadron.exception.exceptions.APIException: Not enough scrap
127.0.0.1 - - [16/Oct/2018 23:48:39] "PUT /drone/7 HTTP/1.1" 500 -

错误处理规范

这是@Hyunwoo 建议的print(app.error_handler_spec) 的输出。

{None: {
    500: {<class 'werkzeug.exceptions.InternalServerError'>: <function error_handler at 0x7fdd0cb6ad08>}, 
    None: {
        <class 'sqlalchemy.exc.IntegrityError'>: <function integrity_error_handler at 0x7fdd0cb6ab70>, 
        <class 'exception.exceptions.APIException'>: <function api_exception_handler at 0x7fdd0cb6abf8>, 
        <class 'exception.exceptions.ValidationException'>: <function validation_exception_handler at 0x7fdd0cb6ac80>
}}}

【问题讨论】:

    标签: python-3.x exception flask


    【解决方案1】:

    我使用app.errorhandler 处理烧瓶中的错误。 (不管是自定义错误,还是std错误)

    # IntegrityError Error handler
    @app.errorhandler(IntegrityError)
    def exception_handler(e):
        return jsonify({'message': e._message().split('"')[2].strip()}), 400
    
    
    # Custom Error handler
    
    # Duplicated column value
    @app.errorhandler(APIException)
    def exception_handler(e):
        return jsonify({'message': e.description}), 400
    

    同样的用法

    @app.route('/')
    def index():
        if something_wrong():
            raise APIException
    
    class ARouteAPI():
        def post(data):
            if not data.something:
                raise APIException("Invalid data error")
    

    不要忘记确保您的处理程序是由烧瓶应用添加的

    >>> print(app.error_handler_spec)
    {None: {None: {<class 'sqlalchemy.exc.IntegrityError'>: <function exception_handler at 0x10ae24158>,
                   <class 'app.error.exc.DuplicatedValueError'>: <function exception_handler at 0x10ae54268>,
                   <class 'app.error.exc.WrongSelectionError'>: <function exception_handler at 0x10ae542f0>},
            404: {<class 'werkzeug.exceptions.NotFound'>: <function exception_handler at 0x10a53c7b8>}}}
    

    【讨论】:

    • 看起来只是票谢谢。我试试看。
    • @Sarcoma 你也可以添加你的堆栈跟踪日志吗?这使得调查问题变得更加容易。
    • 当然,我会在几个小时后再次讨论这个问题,我会告诉你一切进展如何。这看起来像我正在寻找的东西。
    • 我会为你祈祷。祝你好运
    • 非常感谢您的帮助。你肯定在正确的轨道上。不过,我仍然无法找到正确的方法。我更新了我的问题并添加了堆栈跟踪。
    猜你喜欢
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多