处理 Flask 路由中的所有异常

Handle all exceptions in Flask route

我的 Flask 应用程序中有一条简单的路线:

@app.route('/', methods=['GET'])
def homepage():
    return '{}'.format(1 / 0)

当用户访问 site.com/ 时,她应该看到 1/0 的结果。当然那是不可能的,所以 Python 抛出一个错误。

现在,我希望以特殊方式处理我所有端点上的所有错误:我希望它们 return 一个 JSON 响应,例如:

{
    'status_code': 500,
    'status': 'Internal Server Error'
}

我写了一个装饰器来做这个:

def return_500_if_errors(f):
    def wrapper(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except:
            response = {
                'status_code': 500,
                'status': 'Internal Server Error'
            }
            return flask.jsonify(response), 500
    return wrapper

然后我将装饰器添加到端点:

@return_500_if_errors
@app.route('/', methods=['GET'])
def homepage():
    return '{}'.format.(1 / 0)

不过,装饰器好像没有作用。

这是您需要的:

from flask import Flask, jsonify
from functools import wraps

app = Flask(__name__)

def catch_custom_exception(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            return str(e), 500
    return decorated_function

@app.route('/', methods=['GET'])
@catch_custom_exception
def homepage():
    return '{}'.format(1 / 0)

@app.route('/2', methods=['GET'])
def homepage2():
    return '{}'.format(1 / 0)

正如@YiFei 和@Joost 所指出的,问题出在装饰器顺序上。

这确实有效:

def return_500_if_errors(f):
    def wrapper(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except:
            response = {
                'status_code': 500,
                'status': 'Internal Server Error'
            }
            return flask.jsonify(response), 500
    return wrapper

@app.route('/', methods=['GET'])
@return_500_if_errors
def homepage():
    return '{}'.format.(1 / 0)

@Joost 的回答类似但有些不同,因为错误本身会被捕获并返回——而不是标准化的 JSON.

我强烈建议使用 Flask 的 error handler 已经存在的装饰器。

基本上,应该类似于:

# flask will check if raised exception is of type 'SomeException' (or lower)
# if so, will just execute this method
@app.errorhandler(SomeException) 
def handle_error(error):
    response = jsonify(error.to_dict())
    response.status_code = error.status_code
    return response

# An exception will be raised, hopefully to be caught by 'handle_error'    
@app.route('/', methods=['GET'])
def homepage():
    return '{}'.format.(1 / 0)

只需确保要捕获的异常具有 'status_code' 或如果没有则放置 '500'...