2014-10-14 16 views
5

Puoi vedere qui 2 gestori simili: AgeHandler1 e AgeHandler2. Nel primo handler solleviamo semplicemente un'eccezione specifica per restituire un messaggio di errore, nel secondo - restituiamo manualmente un messaggio di errore. Cosa pensi di questi due metodi? Quale metodo è preferibile per un progetto di grandi dimensioni? Qualche altra buona pratica? Grazie per le tue risposte!Un modo migliore per gestire gli errori nel gestore delle richieste di tornado

import logging 
import os.path 
import traceback 

from sys import exc_info 
from tornado import web, options, ioloop 

logger = logging.getLogger(__name__) 


class MyAppException(Exception): 

    def __init__(self, message, code=400, *args, **kwargs): 
     self.message = message 
     self.code = code 
     return super(MyAppException, self).__init__(*args, **kwargs) 

    def __str__(self): 
     return self.message 


class MyAppBaseHandler(web.RequestHandler): 

    def handle_exception(self, e): 
     exc_type, exc_obj, exc_tb = exc_info() 
     logger.error(''.join([line for line in traceback.format_exception(
      exc_type, exc_obj, exc_tb)])) 
     if isinstance(exc_obj, MyAppException): 
      self.set_status(exc_obj.code) 
      self.write({'error': { 
       'message': u'{exc_obj}'.format(exc_obj=exc_obj.message)}}) 
     else: 
      self.set_status(500) 
      fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] 
      self.write({'error': { 
       'message': u'{exc_obj} in {fname} at {line}'.format(
        exc_obj=exc_obj, fname=fname, line=exc_tb.tb_lineno)}}) 


class AgeHandler1(MyAppBaseHandler): 

    def get(self): 
     try: 
      age = self.get_argument('age') 
      age = int(age) 
      if age < 1 or age > 200: 
       raise MyAppException('Wrong age value.') 
      self.write('Your age is {age}'.format(age=age)) 
     except Exception as e: 
      self.handle_exception(e) 


class AgeHandler2(MyAppBaseHandler): 

    def get(self): 
     age = self.get_argument('age') 
     age = int(age) 
     if age < 1 or age > 200: 
      self.set_status(400) 
      self.write('Wrong age value.') 
      return 
     self.write('Your age is {age}'.format(age=age)) 


class MyApplication(web.Application): 

    def __init__(self, **kwargs): 
     kwargs['handlers'] = [ 
      web.url(r'/age1', AgeHandler1, name='age1'), 
      web.url(r'/age2', AgeHandler2, name='age2'), 
     ] 
     kwargs['debug'] = False 
     super(MyApplication, self).__init__(**kwargs) 


if __name__ == '__main__': 
    options.parse_command_line() 
    application = MyApplication() 
    application.listen(5000) 
    ioloop.IOLoop.instance().start() 

Risposte:

""" 
http://127.0.0.1:5000/age1 
500: {"error": {"message": "HTTP 400: Bad Request (Missing argument age) in app.py at 44"}} 
--- 
http://127.0.0.1:5000/age1?age=10 
200: Your age is 10 
--- 
http://127.0.0.1:5000/age1?age=201 
400: {"error": {"message": "Wrong age value."}} 
--- 
http://127.0.0.1:5000/age1?age=abc 
500: {"error": {"message": "invalid literal for int() with base 10: 'abc' in app.py at 45"}} 


http://127.0.0.1:5000/age2 
400: <html><title>400: Bad Request</title><body>400: Bad Request</body></html> 
--- 
http://127.0.0.1:5000/age2?age=10 
200: Your age is 10 
--- 
http://127.0.0.1:5000/age2?age=201 
400: Wrong age value. 
--- 
http://127.0.0.1:5000/age2?age=abc] 
500: <html><title>500: Internal Server Error</title><body>500: Internal Server Error</body></html> 
""" 

risposta

5

In generale l'approccio migliore è quello di ignorare RequestHandler.write_error. Questo è simile al tuo primo approccio, ma non hai bisogno di provare/tranne nel corpo del gestore perché Tornado gestirà ciò per te.

Test espliciti come quelli del tuo secondo esempio sono anche buoni, ma non è pratico rilevare tutti gli errori possibili in questo modo, quindi avrai sempre bisogno di qualcosa per gestire le eccezioni non rilevate.

0

Per i grandi progetti, vorrei provare a astratto da numeri di errore, soprattutto perché la definizione dei codici di stato HTTP non sono nella vostra portata. Per quanto ricordo, c'è almeno una coppia di codici di stato con problemi semantici. Non ricordo quale loro dove.

Tuttavia, per un progetto più ampio, consiglierei di definire le proprie categorie di errore che si desidera supportare e associare tali categorie ai codici HTTP centralmente in base alle proprie esigenze. Quando scoprirai dopo, che dovresti usare un codice di stato diverso per qualche categoria di errore, puoi farlo centralmente.

Logicamente, proverei a calcolare il maggior numero possibile di conoscenze dalla routine di gestione specifica. Il modello ad eccezione, naturalmente, viene qui a portata di mano, ma simile potrebbe essere raggiunto con una chiamata di funzione per la gestione degli errori come:

... 
if age < 1 or age > 200: 
    return self.errorResult('Wrong age value.', WRONG_VALUE) 
... 

o

... 
if age < 1 or age > 200: 
    return self.wrongValue('Wrong age value.') 
... 
Problemi correlati