¿Debo usar códigos de estado HTTP para describir eventos de nivel de aplicación

54

Varios servidores con los que he tratado devolverán HTTP 200 para solicitudes que el cliente debería considerar un error, con algo como 'éxito: falso' en el cuerpo.

Esto no me parece una implementación adecuada de códigos HTTP, particularmente en casos de autenticación fallida. He leído los códigos de error HTTP resumidos de manera bastante sucinta, ya que '4xx' indica que la solicitud no se debe volver a hacer hasta que se modifique, mientras que '5xx' indica que la solicitud puede o no ser válida y se puede volver a intentar, pero no tuvo éxito. En este caso 200: error de inicio de sesión, o 200: no se pudo encontrar ese archivo, o 200: falta el parámetro x, definitivamente parece incorrecto.

Por otro lado, pude ver el argumento de que '4xx' solo debería indicar un problema estructural con la solicitud. Por lo tanto, es correcto devolver 200: usuario / contraseña incorrecta en lugar de 401 sin autorización porque el cliente puede realizar la solicitud, pero resulta ser incorrecta. Este argumento podría resumirse ya que, si el servidor pudo procesar la solicitud y tomar una determinación, el código de respuesta debería ser 200, y el cliente debe verificar el cuerpo para obtener más información.

Básicamente, esto parece ser una cuestión de preferencia. Pero eso no es satisfactorio, así que si alguien tiene una razón por la cual cualquiera de estos paradigmas es más correcto, me gustaría saberlo.

Kagan Mattson
fuente
99
success: falseimplica que la solicitud falló y lo sabes. Eso debería ser un 500. Algo así como su nombre de usuario / contraseña incorrectos sería un 401. Esto no es tan ambiguo.
Pete
44
Esta es una de esas preguntas que pueden invocar guerras religiosas, creo. Para una API RESTful, la respuesta es clara, pero hay otros tipos de API donde HTTP se trata solo como una capa de transporte, y en esos casos, los errores de la aplicación no deberían sangrar a esa capa.
Gort the Robot
55
Cuando realmente no estoy seguro de qué estado http devolver, siempre es tentador ir con 418 "Soy una tetera".
joshp
1
Un ejemplo son las solicitudes y respuestas múltiples (por lotes) . El procesamiento por lotes no es una cosa tranquila; pero los problemas prácticos de eficiencia a menudo requieren algún tipo de apoyo para el procesamiento por lotes sobre los problemas de elegancia.
rwong

Respuestas:

35

Interesante pregunta.

Básicamente, podemos reducir esto a la forma correcta de clasificar las cosas en términos análogos a las capas OSI. HTTP se define comúnmente como un protocolo de nivel de aplicación, y HTTP es de hecho un protocolo genérico de cliente / servidor.

Sin embargo, en la práctica, el servidor es casi siempre un dispositivo de retransmisión, y el cliente es un navegador web, responsable de interpretar y representar el contenido: el servidor simplemente pasa las cosas a una aplicación arbitraria, y esas aplicaciones envían scripts arbitrarios que el navegador Es responsable de la ejecución. La interacción HTTP en sí misma, los formularios de solicitud / respuesta, los códigos de estado, etc., es principalmente una cuestión de cómo solicitar, servir y presentar contenido arbitrario de la manera más eficiente posible, sin interferir. Muchos de los códigos de estado y encabezados están diseñados para estos fines.

El problema al tratar de aprovechar el protocolo HTTP para manejar flujos específicos de la aplicación, es que te queda una de dos opciones: 1) Debes hacer que tu lógica de solicitud / respuesta sea un subconjunto de las reglas HTTP; o 2) Debe reutilizar ciertas reglas, y luego la separación de las preocupaciones tiende a volverse confusa. Esto puede verse bien y limpio al principio, pero creo que es una de esas decisiones de diseño que terminas lamentando a medida que tu proyecto evoluciona.

Por lo tanto, diría que es mejor ser explícito sobre la separación de protocolos. Deje que el servidor HTTP y el navegador web hagan lo suyo y que la aplicación haga lo suyo. La aplicación debe poder realizar solicitudes, y necesita las respuestas, y su lógica sobre cómo solicitar, cómo interpretar las respuestas, puede ser más (o menos) compleja que la perspectiva HTTP.

El otro beneficio de este enfoque, que vale la pena mencionar, es que las aplicaciones, en términos generales, no deberían depender de un protocolo de transporte subyacente (desde un punto de vista lógico). HTTP en sí mismo ha cambiado en el pasado, y ahora tenemos el inicio de HTTP 2, después de SPDY. Si ve que su aplicación no es más que un complemento de funcionalidad HTTP, es posible que se quede atascado allí cuando las nuevas infraestructuras se hagan cargo.

Ñame Marcovic
fuente
8
Muy perspicaz. El argumento más fuerte aquí es la falta de coincidencia (impedancia) entre los códigos de estado HTTP y los valores de retorno de su aplicación. Esto puede convertirse en una pesadilla a largo plazo. Además, apoyo la separación de preocupaciones entre el transporte (HTTP) y la carga útil (datos de la aplicación). Si escribe incorrectamente la URL de un punto final de servicio, obtiene un 404. Si solicita al servicio un elemento inexistente, recibirá un mensaje específico de la aplicación (tal vez con información adicional que pueda usar para resolver el problema).
2
Si escribe incorrectamente la URL, es posible que ni siquiera termine en el servidor correcto, y entonces podría pasar cualquier cosa .
gnasher729
Este es un aspecto muy bien matizado. Creo que el problema de que HTTP se convierta en una capa de pseudo-transporte es el verdadero problema para tomar una determinación. La mayoría de las veces me encuentro con esta pregunta cuando tienes un servidor nginx o apache que representa un servidor nodejs, donde el proxy ya tiene reglas para enviar estos códigos, y la pregunta es si es apropiado que el backend se ajuste al estándar. En algunos de esos casos, puede haber una razón de diseño para no enviar un código de error, ya que nginx puede interpretarlo como 'backend down'.
Kagan Mattson
44
Estoy de acuerdo. No hay nada de malo en que se informe un error de la capa de aplicación en una respuesta HTTP 200. El 200 indica que la solicitud / respuesta HTTP en sí fue exitosa, sin decir nada sobre su contenido o la semántica de la capa de aplicación que se invocó en ese momento.
Lightness compite con Monica el
22

Esta pregunta está un poco basada en la opinión, pero de cualquier manera.

A mi modo de ver, 200 puede servir "errores suaves". Cuando se trata de crear API, trato de distinguir entre estos y los "errores duros".

Los "errores suaves" se mostrarán con un código de estado de 200, pero contendrán una descripción del error y un estado de éxito de false. Los "errores suaves" solo ocurrirán cuando el resultado sea "como se esperaba", pero no un éxito en el sentido más estricto.

Es importante tener en cuenta que los "errores suaves" son más una pista para el implementador. Por lo tanto, es importante proporcionar también más información sobre el error, como un mensaje de error legible por humanos y / o algún tipo de código que se pueda utilizar para proporcionar comentarios al usuario final. Estos errores proporcionan al implementador (y al usuario final) más información sobre lo que sucedió en el lado del servidor .

Por ejemplo, supongamos que tiene una API con una función de búsqueda, pero durante una búsqueda, no se obtienen resultados. Esto no es erróneo, pero tampoco es un "éxito", ni en el sentido más estricto de la definición.

Ejemplo formateado como JSON:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

Los "errores duros", por otro lado, recibirán un código de estado que se recomienda para el error. ¿El usuario no ha iniciado sesión? - 403 / 401. ¿Entrada mal formada? - 400. ¿Error del servidor? - 50X. Y así.

De nuevo, está un poco basado en la opinión. Algunas personas quieren tratar todos los errores por igual, "error duro" todo. ¿No hay resultados de búsqueda? Eso es un 404! En el otro lado de la moneda, ¿no hay resultados de búsqueda? - Esto es como se esperaba, no hay error.

Otro factor importante a tener en cuenta es su arquitectura, por ejemplo; si interactúa con su API utilizando solicitudes XHR de JavaScript y jQuery o AngularJS. Estos "errores duros" deberán manejarse con una devolución de llamada separada, mientras que los "errores blandos" pueden manejarse con la devolución de llamada "correcta". Sin romper nada, el resultado sigue siendo "como se esperaba". El código del lado del cliente puede ver el estado de éxito y el código (o mensaje). E imprímalo al usuario final.

die maus
fuente
2
En realidad, clasificar eso como un error en el nivel API es una decisión curiosa. Aunque el cliente puede, a su discreción, clasificarlo como inesperado a nivel de usuario.
Deduplicador
1
Hay muchas cosas que deben tenerse en cuenta. Todo depende de la implementación de la API. También es una vez más, un poco basado en opiniones y también a lo que la API define como "éxito" y / o "error". La "success": falsebandera es más una pista para el implementador de que algo está pasando. Por lo general, debe ir con un código de estado interno . Cualquiera "code": "NORESULTS"o un código numérico, cualquiera que sea el creador de la API. Está principalmente allí para que quien implemente la API pueda deducir información sobre lo que sucedió en el servidor.
die maus
15

Hay dos aspectos de una API: el esfuerzo para implementar la API y el esfuerzo de todos los clientes para usar la API correctamente.

Como autor del cliente, sé que cuando envío una solicitud a un servidor web, es posible que reciba un error (nunca se comunicó correctamente con el servidor) o una respuesta con un código de estado. Tengo que manejar los errores. Tengo que manejar una buena respuesta. Tengo que manejar las respuestas esperadas, documentadas, "malas". Tengo que manejar lo que sea que vuelva.

Al diseñar la API, debe ver qué es lo más fácil de procesar para el cliente. Si el cliente envía una solicitud bien formada y usted puede hacer lo que la solicitud le pide que haga, entonces debe dar una respuesta en el rango de 200 (hay algunos casos en los que es apropiado un número distinto de 200 en ese rango).

Si el cliente pregunta "dame todos los registros como ...", y hay cero, entonces un 200 con éxito y una matriz de cero registros es completamente apropiado. Los casos que mencionas:

"Error de inicio de sesión" generalmente debería ser un 401. "No se pudo encontrar el archivo" debería ser un 404. El "parámetro x faltante" debería ser alrededor de 500 (en realidad, un 400 si el servidor se da cuenta de que la solicitud es incorrecta y 500 si el servidor está totalmente confundido por mi solicitud y no tiene idea de lo que está pasando). Devolver 200 en estos casos no tiene sentido. Simplemente significa que, como autor de un cliente, no puedo simplemente mirar el código de estado, también tengo que estudiar la respuesta. No puedo decir simplemente "estado 200, genial, aquí están los datos".

Especialmente el "parámetro faltante", eso no es algo que pueda manejar . Significa que mi solicitud es incorrecta. Si mi solicitud es incorrecta, no tengo una reserva para solucionar esa solicitud incorrecta; para comenzar, enviaría una solicitud correcta. Ahora me veo obligado a manejarlo. Me sale un 200 y tengo que comprobar si hay una respuesta "falta un parámetro". Eso es horrible.

Al final, hay una docena o dos códigos de estado para manejar muchas situaciones diferentes, y debe usarlos.

gnasher729
fuente
3
Cuando me conecto a una API, personalmente prefiero obtener 200 en un 'archivo no encontrado' cuando me conecto a un punto final válido, ya que mi manejo de HTTP no tiene que sangrar en la capa que maneja la API encima.
whatsisname
44
El "parámetro x faltante" debe ser 400 BAD_REQUEST porque es el cliente el que hace algo mal. 500 INTERNAL_SERVER_ERROR debe reservarse para los casos en que el servidor está haciendo algo incorrecto. Un 500 implica que el cliente podría intentarlo de nuevo. Un 400 implica que alguien debe ir a arreglar el cliente.
Gort the Robot
1
Si está escribiendo una interfaz RESTful, la URL identifica un objeto específico y, por lo tanto, es apropiado un 404. Conceptualmente, lo mismo se /customers/premium/johndoe.jsonrefiere a un cliente que no está en la base de datos y si se /files/morefiles/customers.htmlrefiere a una página que no está en el sistema de archivos.
Gort the Robot
@whatsisname Lo que estás diciendo tiene sentido porque entonces no está claro si el punto final es malo o si el recurso no existe. También puede argumentar que si el punto final es válido o no, no existe ningún recurso en esa dirección, por lo que a 404es correcto en ambos casos.
Pete
2
Una cosa que no he visto mencionada es que cuando se superponen errores de aplicación en códigos de estado HTTP, puede perder información. Si la aplicación solo devuelve un 404 y nada más, no sabe si fue porque su API devolvió un 404 o porque el servidor no pudo encontrar el archivo. Eso podría agregar un paso adicional a su depuración.
AmadeusDrZaius