2015-03-29 11 views
16

C'è un modo per aggiungere un gestore globale di errori catch-all in cui posso modificare la risposta a una risposta JSON generica?Global error handler per qualsiasi eccezione

Non è possibile utilizzare il segnale got_request_exception poiché non è consentito modificare la risposta (http://flask.pocoo.org/docs/0.10/signals/).

Al contrario tutti i gestori di segnale vengono eseguiti in ordine indefinito e non modificano alcun dato.

preferirei non avvolgere la funzione app.handle_exception come ci si sente come API interna. Credo di essere alla ricerca di qualcosa di simile:

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

Annotare il errorhandler non prende alcun parametro, il che significa che sarebbe catturare tutte le eccezioni/codici di stato che non ha un gestore di errore specifico ad essi connessi. So che posso usare errorhandler(500) o errorhandler(Exception) per rilevare eccezioni, ma se faccio abort(409) per esempio, restituirà comunque una risposta HTML.

risposta

24

È possibile utilizzare @app.errorhandler(Exception):

Demo (l'assegno HTTPException assicura che il codice di stato è conservato):

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) 

uscita:

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

Se anche voi volete ignorare la eccezioni HTML predefinite da Flask (in modo che restituiscano anche JSON), aggiungere quanto segue prima di app.run:

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

Per le versioni più vecchie Flask (< = 0.10.1, vale a dire qualsiasi/versione principale non-git al momento), aggiungere il seguente codice per l'applicazione per registrare gli errori HTTP in modo esplicito:

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

Questo è così strano. Sto copiando il tuo codice in una shell Python con Flask 0.10.1, e ottengo ancora errori HTML quando richiedi questi endpoint usando curl. Quale versione di Flask stai usando? – joscarsson

+0

Ah, apparentemente qualcosa è cambiato tra 0.10.1 e la versione di git con cui lo stavo testando. – ThiefMaster

+0

https://github.com/mitsuhiko/flask/blob/0.10.1/flask/app.py#L1086 - a quanto pare utilizza solo il codice dell'eccezione nelle versioni precedenti. – ThiefMaster

4

Lontano dalla elegante, ma le seguenti opere per legare tutte le sottoclassi di HTTPException ad un unico gestore degli errori:

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) 
9

Questo è Flask 0,12 compatibile, e una buona soluzione al problema (che permette di ren errori der in JSON o qualsiasi altro formato)

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

+0

grazie. questo ha funzionato. – JSBach