Глобальный обработчик ошибок для любого исключения

Есть ли способ добавить глобальный обработчик ошибок catch-all, в котором я могу изменить ответ на общий ответ JSON?

Я не могу использовать сигнал got_request_exception, так как не разрешено изменять ответ (http://flask.pocoo.org/docs/0.10/signals/).

В отличие от всех обработчиков сигналов выполняются в порядке undefined и не изменяют никаких данных.

Я бы предпочел не обернуть функцию app.handle_exception, поскольку это похоже на внутренний API. Думаю, я за чем-то вроде:

 @app.errorhandler()
 def handle_global_error(e):
     return "Global error"

Обратите внимание, что errorhandler не принимает никаких параметров, что означает, что он поймает все коды исключений/состояний, которые не имеют привязанного к ним конкретного обработчика ошибок. Я знаю, что могу использовать errorhandler(500) или errorhandler(Exception) для исключения исключений, но если я делаю abort(409), например, он все равно вернет ответ HTML.

Ответы

Ответ 1

Вы можете использовать @app.errorhandler(Exception):

Демо (проверка HTTPException гарантирует сохранение кода состояния):

from flask import Flask, abort, jsonify
from werkzeug.exceptions import HTTPException

app = Flask('test')

@app.errorhandler(Exception)
def handle_error(e):
    code = 500
    if isinstance(e, HTTPException):
        code = e.code
    return jsonify(error=str(e)), code

@app.route('/')
def index():
    abort(409)

app.run(port=1234)

Вывод:

$ http get http://127.0.0.1:1234/
HTTP/1.0 409 CONFLICT
Content-Length: 31
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:54 GMT
Server: Werkzeug/0.10.1 Python/3.4.3

{
    "error": "409: Conflict"
}

$ http get http://127.0.0.1:1234/notfound
HTTP/1.0 404 NOT FOUND
Content-Length: 32
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:58 GMT
Server: Werkzeug/0.10.1 Python/3.4.3

{
    "error": "404: Not Found"
}

Если вы также хотите переопределить исключения HTML по умолчанию из Flask (чтобы они также возвращали JSON), добавьте следующее до app.run:

from werkzeug.exceptions import default_exceptions
for ex in default_exceptions:
    app.register_error_handler(ex, handle_error)

Для более старых версий Flask (< = 0.10.1, то есть любой версии git/master в данный момент), добавьте следующий код в приложение, чтобы явно зарегистрировать ошибки HTTP:

from werkzeug import HTTP_STATUS_CODES
for code in HTTP_STATUS_CODES:
    app.register_error_handler(code, handle_error)

Ответ 2

Это совместимое с Flask 0.12 и очень хорошее решение проблемы (позволяет отображать ошибки в JSON или в любом другом формате)

from functools import wraps
from flask import Flask, redirect, jsonify
app = Flask(__name__)

def get_http_exception_handler(app):
    """Overrides the default http exception handler to return JSON."""
    handle_http_exception = app.handle_http_exception
    @wraps(handle_http_exception)
    def ret_val(exception):
        exc = handle_http_exception(exception)    
        return jsonify({'code':exc.code, 'message':exc.description}), exc.code
    return ret_val

# Override the HTTP exception handler.
app.handle_http_exception = get_http_exception_handler(app)

https://github.com/pallets/flask/issues/671#issuecomment-12746738

Ответ 3

Далеко не изящный, но следующие работы для привязки всех подклассов HTTPException к одному обработчику ошибок:

from flask import jsonify
from werkzeug.exceptions import HTTPException

def handle_error(error):
    code = 500
    if isinstance(error, HTTPException):
        code = error.code
    return jsonify(error='error', code=code)

for cls in HTTPException.__subclasses__():
    app.register_error_handler(cls, handle_error)