捕获Flask API中引发的自定义异常。引发的所有异常最终导致500错误 [英] Catching custom exceptions raised in Flask API. All exceptions raised end up in 500 Error

查看:106
本文介绍了捕获Flask API中引发的自定义异常。引发的所有异常最终导致500错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to be able to raise validation and other exceptions in my API and catch them in a wrapped view that will return the error message as JSON.

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

I thought I could use something like this:

class APIException(Exception):

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



捕获异常



Catch Exceptions

# 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



路线



Route

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



API处理后



API processing post

class ARouteAPI():

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

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

The problem I'm having is that whatever exception I throw it keeps bubbling up to a full Exception and hitting the 500 so it never returns the APIException.

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

Does anyone know why? How to fix it?

或者还有更好的方法来处理此问题吗?

Alternatively is there a better way to handle this?

对此仍然是一场噩梦。

Still having a nightmare with this.

更好的处理方法是使用 @ app.errorhandler 装饰器(在我的情况下为 @router 是我的蓝图名称,因此我使用的是 @ router.errorhandler ),如@Hyunwoo所建议。

The better way to handle it is to use the @app.errorhandler decorator (in my case @router is my blueprint name so I'm using @router.errorhandler instead), as suggested by @Hyunwoo.

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

However, no matter what exception is thrown it always ends up hitting a 500 error and I have no idea why.

我发现了类似的示例,其中调试模式导致问题重发,我以为可能会引起问题,但我将调试模式设置为 false

I've found similar examples where debug mode causes reraising of issues, that I thought maybe causing issues but I have debug mode set to 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



StackTrace



StackTrace

[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 -



错误处理程序规范



这是 print(申请者ror_handler_spec),由@Hyunwoo建议。

Error Handler Spec

Here is the output of print(app.error_handler_spec) as suggested by @Hyunwoo.

{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>
}}}


推荐答案

我使用了 app.errorhandler 用于处理烧瓶中的错误。 (无论是自定义错误还是标准错误)

I used app.errorhandler for handling errors in flask. (No matter whether it is custom error, or std error)

# 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

在视图中使用相同的用法

And same usage in view

@app.route('/')
def index():
    if something_wrong():
        raise APIException

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

别忘了确保烧瓶应用添加了处理程序

Don't forget to make sure your handlers are added by flask app

>>> 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>}}}

这篇关于捕获Flask API中引发的自定义异常。引发的所有异常最终导致500错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆