2012-03-21 10 views
10

Estoy usando ajax para mejorar la experiencia del usuario en mi proyecto Django. Mi preocupación aquí es cómo responder el error al navegador correctamente. Por lo que sé, puedo:Django ajax error response best practice

  1. validar los datos de solicitud pieza por pieza y guardar la excepción uno por uno. Si sucede algo malo, plantee Http404 u otra excepción para anunciar explícitamente que se ha producido un error. O
  2. simplemente escriba el código sin excepción y suponga que funcionará. Si algo malo sucede, la excepción no detectada podría causar un error interno del servidor, que todavía es un error para el navegador

Para mí, el método fisrt parece más ortodoxo, como en Pitón la filosofía de "Explícito es mejor que Implícito "realmente cuenta". Pero dado que todo tipo de comprobación de excepciones se eliminan del segundo, es más limpio, menos fragmentado y más legible.

Estoy usando jQuery para manejar la solicitud/respuesta ajax y ambos métodos parecen funcionar. Mis preguntas son:

  1. ¿Ambos métodos son aceptables?
  2. ¿Fallará el segundo método para otras bibliotecas de Javascript?
  3. ¿Cuál es la mejor práctica para esto?

PS. Hago validación de datos esenciales. Por favor, no te pierdas el tema por eso. :)

+0

Debe marcar una de las respuestas como correctas y adelantar las que le sirvieron. Es una buena práctica si tiene la intención de seguir usando este sitio, así como un buen gesto para aquellos que se tomaron el tiempo para responderle :) – Sid

+0

@Sid Gracias por su amable guía :). Creo que mi pregunta no ha sido respondida (pero he elegido la mejor respuesta en este momento). Y realmente lo siento, pero mi reputación no es suficiente para un voto popular. – kavinyao

+0

No tiene que elegir la mejor respuesta si su pregunta no ha sido completamente respondida. Lo siento, no fue mi intención apresurarte :) – Sid

Respuesta

17

Si devuelve una respuesta con un código de estado 4xx o 5xx esto es un error, y dará lugar a jQueries error manejador. Aunque ciertamente es posible sencilla estado de retorno 200 cada vez y utilizar un campo de "error" en la respuesta JSON (como lo sugiere dm03514) esto es malo por dos razones:

  1. Viola buenas prácticas HTTP. Hay una razón por qué hay un montón de los códigos de error definidos

  2. no puede utilizar el hecho de que jQuery ya tiene un controlador de errores que le permite separar el comportamiento normal de la gestión de errores.

mayoría de las veces la respuesta de error será muy diferente de la respuesta de no error Por lo tanto, simplemente no tiene sentido poner el manejo de estos mensajes en una sola pieza de código JS. Entonces, para resumir, use una respuesta JSON con el estado 200 para sus respuestas normales y devuelva una respuesta 4xx/5xx (¡apropiado!) Para los errores. También pueden transportar la carga JSON, por lo que su lado del servidor puede agregar detalles adicionales sobre el error.

+0

Realmente aprecio su aclaración. Entonces, en realidad, debería usar las subclases de 'HttpResponse', p. Ej. 'HttpResponseNotFound', para notificar al lado del navegador que sucedió algo malo y desencadenar el controlador' error' como se esperaba, ¿verdad? – kavinyao

0

No puedo responder si ambos métodos son aceptables, pero solo puedo decirte lo que hago. En mi opinión cojo algunos errores específicos/explícitos tales como:

  • params no válidos o faltantes en la post
  • errores de alto nivel, tales como nombre de usuario ya presente en la base de datos (en una situación de registro para, por ejemplo)
  • Todos otros errores del sistema

Creo que si se realiza una clasificación de sus errores, ya que algunos errores específicos que el usuario debe conocer y entonces todo lo demás, entonces su código tendrá como máximo 2 o 3 de retorno con rutas de error, que en mi humilde opinión ISN' tan mal utilizo JSON para devolver errores y mi estructura es por lo general como:

respons={} 
response["error|ok"] 
response["msg"]="User not found" 
response["type"]=ERROR_TYPE # only applicable for errors 

Obviamente, esto es bastante básico, pero es de esperar que da una idea general. Recomendaría no permitir que el usuario vea el error del servidor interno generado por el sistema. Esa es una experiencia de usuario horrible, incluso para aplicaciones internas.

Espero que esto ayude.

+0

Después de leer las respuestas, he llegado a comprender que lograr el mismo efecto no justifica mi método (el segundo). ¡Gracias! – kavinyao

0

No tomaría ninguno de los enfoques sugeridos. Sugeriría algo como lo que Sid dijo. ¿Por qué no quieres escribir un código libre de errores?

Intentaré solucionar todos los errores y errores posibles en el código que escribo en todo momento. Esto incluye validar la entrada del usuario. Con ajax creo que es importante devolver los mensajes al usuario. Esto se logra fácilmente con json.

response_dict = {} 
try: 
    # do action that could cause an error 
except ExpectedError as e: 
    response_dict['success'] = False 
    response_dict['message'] e.msg # or custom message 
    return HttpResponse(json.dumps(repsonse_dict)) 

después en la llamada ajax posterior Asegúrese de que la respuesta es válida, si no se alerta al usuario de lo que han hecho mal. no los dejes colgando, ¡estás haciendo una aplicación para ellos!

+0

Veo tu punto. ¿Pero hay alguna manera _explicit_ de desencadenar el argumento de error de jQuery.ajax? Supongo que se llama al argumento de éxito cuando la solicitud realmente tiene éxito. – kavinyao

0

Utilice la opción 1 pero no del todo como usted la describe; debe devolver una HttpResponse con el código de estado 200 que indica que se produjo un error de validación en el contenido de la respuesta, luego, cuando procesa la respuesta en el cliente con JQuery simplemente verifica el contenido de la respuesta y detecta si hubo errores de validación.

Ejemplo de una cadena JSON para el HttpResponse:

{"errors": "true", "messages": ["Error #1", "Error #2", "etc."]} 

Opción 2 no es una buena práctica porque los errores de servidor interno sucede cuando hay una excepción no detectada que ese fue lanzado por el servidor y por lo general es desconocido para el programador.

No utilice códigos de estado HTTP para denotar errores de validación, ese no es su propósito.

+0

Gracias por su sugerencia. Pero si devuelvo HttpResponse así en el ejemplo, se llamaría a la función de éxito de jQuery.ajax, ¿verdad? Me pregunto para qué sirve la función de error. – kavinyao

+0

Sí, se llamará a la función de éxito. En JQuery [documentación] (http://api.jquery.com/jQuery.ajax/) dice: ** se invocan devoluciones de llamada de error, en el orden en que se registran, si la solicitud falla. **, entonces solo el error el controlador se activará si se produce algún error en la solicitud y no en la información enviada dentro de la solicitud. –

1

En mi opinión:

  1. el segundo método no es aceptable.
  2. no fallará ya que el servidor aún enviará una respuesta http.
  3. Déjeme decirle lo que hago en mis proyectos:

cuando mi proyecto comienza, siempre antes de añadir un módulo denominado errors en la parte superior de la estructura de carpetas, en primer lugar, voy a escribir una clase de excepción base que hereda de Exception, luego escribe algunas clases de excepciones comunes como ObjectNotFound, ValidationError según mi experiencia. Cuando creo que debería aparecer una excepción en mi código, usaré excepciones de este módulo, y cuando encuentre que se debe manejar un nuevo tipo de excepción, escribiré una nueva excepción.

Entonces es el trabajo de cómo manejarlos. Como se está utilizando Django, es muy fácil de capturar las excepciones a través de un middleware, se puede escribir algo como esto:

from youproject import errors 

# categorize your exceptions 
400_ERRORS = (errors.ValidationError, errors.ParametersMissing,) 
403_ERRORS = (errors.AuthenticationError,) 
404_ERRORS = (errors.ObjectNotFound, errors.ResourceNotExist,) 

class ExceptionHandleMiddleware(object): 
    def process_exception(self, request, e): 
     # set status_code by category of the exception you caught 
     if isinstance(e, 400_ERRORS): 
      status_code = 400 
     elif isinstance(e, 403_ERRORS): 
      status_code = 403 
     elif isinstance(e, 404_ERRORS): 
      status_code = 404 
     else: 
      # if the exception not belone to any one you expected, 
      # or you just want the response to be 500 
      status_code = 500 
      # you can do something like write an error log or send report mail here 
      logging.error(e) 

     response_dict = { 
      'status': 'error', 
      # the format of error message determined by you base exception class 
      'msg': str(e) 
     } 
     if settings.debug: 
      # you can even get the traceback infomation when you are in debug mode 
      response_dict['traceback'] = traceback.format_exc() 

     # set header and return the response 
     .... 

El código anterior es un resumen de cómo lo hago mango excepción en mis proyectos, en general , se trata de control de excepciones precisas, categorización de excepciones adecuada y, por supuesto, la filosofía 'Explicit is better than Implicit'.

ACTUALIZACIÓN === === Cuando se trata de cómo hacer frente a las respuestas correspondientes en ajax, puede utilizar la nueva característica de jquery1.5 statusCode:

$.ajax({ 
    statusCode: { 
    404: function() { 
     alert('page not found'); 
    } 
    } 
}); 

de la documentación de jQuery :

Un mapa de códigos numéricos HTTP y funciones para llamar cuando la respuesta tiene el código correspondiente.Por ejemplo, lo siguiente será alerta cuando el estado de respuesta es un 404

+0

Gracias por su solución. Categorizar los errores comunes y manejarlos con middleware parece una solución ordenada y escalable. ¿Este enfoque se usa comúnmente? – kavinyao

+0

Bueno, diseñar sus excepciones personalizadas es una forma sugerida para escribir programas robustos, en cuanto a Django, no estoy seguro de si esta es la mejor solución ya que no la he usado por períodos. Pero Django sigue siendo python, si piensas que esto es pitónico, simplemente funciona. – Reorx

Cuestiones relacionadas