web-dev-qa-db-fra.com

Gestionnaire d'erreurs global pour toute exception

Existe-t-il un moyen d'ajouter un gestionnaire d'erreur global passe-partout dans lequel je peux changer la réponse en une réponse JSON générique?

Je ne peux pas utiliser le signal got_request_exception, Car il n'est pas autorisé de modifier la réponse ( http://flask.pocoo.org/docs/0.10/signals/ ).

En revanche, tous les gestionnaires de signaux sont exécutés dans un ordre indéfini et ne modifient aucune donnée.

Je préférerais ne pas envelopper la fonction app.handle_exception Car cela ressemble à une API interne. Je suppose que je recherche quelque chose comme:

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

Notez que errorhandler ne prend aucun paramètre, ce qui signifie qu'il intercepterait tous les codes d'exception/d'état qui ne sont pas associés à un gestionnaire d'erreur spécifique. Je sais que je peux utiliser errorhandler(500) ou errorhandler(Exception) pour intercepter des exceptions, mais si je fais abort(409) par exemple, il retournera toujours une réponse HTML.

39
joscarsson

Vous pouvez utiliser @app.errorhandler(Exception):

Démo (la vérification HTTPException garantit que le code d'état est conservé):

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)

Sortie:

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

Si vous souhaitez également remplacer les exceptions HTML par défaut de Flask (afin qu'elles renvoient également JSON), ajoutez ce qui suit avant app.run:

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

Pour les anciennes versions Flask (<= 0.10.1, c'est-à-dire toute version non git/master pour le moment), ajoutez le code suivant à votre application pour enregistrer explicitement les erreurs HTTP:

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

Ceci est Flask 0.12 compatible, et une très bonne solution au problème (il permet de rendre des erreurs en JSON ou tout autre format)

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

10
lol

Loin d'être élégant, mais ce qui suit fonctionne pour lier toutes les sous-classes de HTTPException à un seul gestionnaire d'erreur:

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)
6
bwind

Une manière plus propre de l'implémenter dans Flask> = 0.12 serait d'enregistrer explicitement le gestionnaire pour chaque exception Werkzeug:

from flask import jsonify
from werkzeug.exceptions import HTTPException, default_exceptions

app = Flask('test')

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

for exc in default_exceptions:
    app.register_error_handler(exc, handle_error)
2
nfvs

Basé sur Pages d'erreur simples (non HTML) dans REST api

Je voulais retourner json sans changer aucun de mon code, donc j'ai juste ajouté ce qui suit en haut de mon code

@app.errorhandler(500)
def error_500(exception):
    return jsonify({"error": str(exception)}), 500, {'Content-Type': 'application/json'}

@app.errorhandler(400)
def error_400(exception):
    return jsonify({"error": str(exception)}), 400, {'Content-Type': 'application/json'}
0
julianalimin

Si les exceptions ne fonctionnent pas, vous pouvez essayer app.register_error_handler (ou utiliser app.errorhandler de manière non décorative)

Source: https://github.com/pallets/flask/issues/1837

0
Suresh Ganta