REST API 404: URI malo,o Falta de Recursos?


Estoy construyendo una API REST, pero me he encontrado con un problema.

Parece que la práctica aceptada en el diseño de una API REST es que si el recurso solicitado no existe, se devuelve un 404.

Sin embargo, para mí, esto agrega ambigüedad innecesaria. HTTP 404 se asocia más tradicionalmente con un URI malo. Así que en efecto estamos diciendo " O has llegado al lugar correcto, pero ese registro específico no existe, o no hay tal ubicación en Internet! Realmente no. seguro cuál..."

Considere el siguiente URI:

http://mywebsite/api/user/13

Si me devuelven un 404, ¿es porque el Usuario 13 no existe? O es porque mi URL debería haber sido:

http://mywebsite/restapi/user/13

En el pasado, acabo de devolver un resultado NULO con un código de respuesta HTTP 200 OK si el registro no existe. Es simple, y en mi opinión muy limpio, incluso si no es necesariamente una práctica aceptada. ¿Pero hay una mejor manera de hacer esto?

Author: MC Emperor, 2012-03-29

9 answers

404 es solo el código de respuesta HTTP. Además de eso, puede proporcionar un cuerpo de respuesta y / u otros encabezados con un mensaje de error más significativo que los desarrolladores verán.

 66
Author: Robert Levy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-29 17:52:23

Utilice 404 si el recurso no existe. No devuelvas 200 con un cuerpo vacío.

Esto es similar a undefined vs cadena vacía (por ejemplo, "") en la programación. Si bien es muy similar, definitivamente hay una diferencia.

404 significa que no existe nada en ese URI (como una variable indefinida en la programación). Regresar 200 con un cuerpo vacío significa que algo existe allí y que algo está vacío en este momento (como una cadena vacía en programación).

404 no significa que fuera un "mal URI". Hay códigos HTTP especiales destinados a errores URI (por ejemplo, 414 Request-URI Too Long).

 36
Author: nategood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-30 18:25:16

Como con la mayoría de las cosas, "depende". Pero para mí, su práctica no es mala y no va en contra de la especificación HTTP per se. Sin embargo, aclaremos algunas cosas.

Primero, los URI deben ser opacos. Incluso si no son opacas para las personas, son opacas para las máquinas. En otras palabras, la diferencia entre http://mywebsite/api/user/13, http://mywebsite/restapi/user/13 es lo mismo que la diferencia entre http://mywebsite/api/user/13 y http://mywebsite/api/user/14 es decir, no lo mismo no es el mismo período. Así que un 404 sería completamente apropiado para http://mywebsite/api/user/14 (si no existe tal usuario) pero no necesariamente la única respuesta apropiada.

También puede devolver una respuesta 200 vacía o más explícitamente una respuesta 204 (Sin contenido). Esto transmitiría algo más al cliente. Implicaría que el recurso identificado por http://mywebsite/api/user/14 no tiene contenido o es esencialmente nada. Significa que existe tal recurso. Sin embargo, esto no significa necesariamente que usted está afirmando que hay algún usuario persistió en un almacén de datos con id 14. Esa es su preocupación privada, no la preocupación del cliente que hace la solicitud. Por lo tanto, si tiene sentido modelar sus recursos de esa manera, adelante.

Hay algunas implicaciones de seguridad al dar a sus clientes información que les haría más fácil adivinar URI legítimos. Devolver un 200 en misses en lugar de un 404 puede darle al cliente una pista de que al menos la parte http://mywebsite/api/user es correcta. Un cliente malicioso podría seguir probando diferentes enteros. Pero para mí, un malintencionado el cliente sería capaz de adivinar la parte http://mywebsite/api/user de todos modos. Un mejor remedio sería usar UUID. Es decir, http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 es mejor que http://mywebsite/api/user/14. Haciendo eso, usted podría utilizar su técnica de devolver 200 sin dar mucho lejos.

 16
Author: jhericks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-29 22:07:18

404 No encontrado técnicamente significa que uri actualmente no mapea a un recurso. En su ejemplo, interpreto una solicitud a http://mywebsite/api/user/13 que devuelve un 404 para dar a entender que esta url fue nunca asignada a un recurso. Para el cliente, ese debería ser el final de la conversación.

Para abordar las preocupaciones con la ambigüedad, puede mejorar su API proporcionando otros códigos de respuesta. Por ejemplo, supongamos que desea permitir que los clientes emitan solicitudes GET la url http://mywebsite/api/user/13, desea comunicar que los clientes deben usar la url canónica http://mywebsite/restapi/user/13. En ese caso, es posible que desee considerar la emisión de una redirección permanente devolviendo un 301 Movido Permanentemente y proporcionar la url canónica en el encabezado Location de la respuesta. Esto le dice al cliente que para futuras solicitudes debe usar la url canónica.

 8
Author: Ralph Allan Rice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-07 16:20:51

Este viejo pero excelente artículo... http://www.infoq.com/articles/webber-rest-workflow dice esto al respecto...

404 No encontrado - El servicio es demasiado perezoso (o seguro) para darnos una razón real por la que nuestra solicitud falló, pero cualquiera que sea la razón, tenemos que lidiar con ella.

 7
Author: Michael Dausmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-02 22:43:18

Así que, en esencia, parece que la respuesta podría depender de cómo se forma la solicitud.

Si el recurso solicitado forma parte del URI según una solicitud a http://mywebsite/restapi/user/13 y el usuario 13 no existe, entonces un 404 es probablemente apropiado e intuitivo porque el URI es representativo de un usuario/entidad/documento/etc inexistente. Lo mismo sucedería para la técnica más segura usando un GUID http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 y el argumento api/restapi anterior.

Sin embargo, si se incluyó el ID de recurso solicitado en el encabezado de la solicitud [incluya su propio ejemplo], o de hecho, en el URI como un parámetro, por ejemplo http://mywebsite/restapi/user/?UID=13 entonces el URI todavía sería correcto (porque el concepto de USUARIO sale en http://mywebsite/restapi/user/); y por lo tanto la respuesta podría esperarse razonablemente que sea un 200 (con un mensaje apropiadamente detallado) porque el usuario específico conocido como 13 no existe pero el URI sí. De esta manera estamos diciendo que el URI es bueno, pero la solicitud de datos no tiene contenido.

Personalmente un 200 todavía no se siente bien (aunque he argumentado anteriormente que sí). Un código de respuesta 200 (sin una respuesta detallada) podría hacer que un problema no se investigue cuando se envía un ID incorrecto, por ejemplo.

Un mejor enfoque sería enviar una respuesta 204 - No Content. Esto es compatible con la descripción del w3c * El servidor ha cumplido con la solicitud, pero no necesita devolver una entidad-cuerpo, y es posible que desee devolver metainformación actualizada.*1 La confusión, en mi opinión, es causada por la entrada de Wikipedia que dice 204 Sin contenido: el servidor procesó correctamente la solicitud, pero no devuelve ningún contenido. Normalmente se usa como respuesta a una solicitud de eliminación exitosa. La última frase es altamente discutible. Considere la situación sin esa oración y la solución es fácil: simplemente envíe un 204 si la entidad no existe. Incluso hay un argumento para devolver un 204 en lugar de un 404, la solicitud ha sido procesada y no se ha devuelto ningún contenido. Tenga en cuenta sin embargo, 204 no permitir contenido en el cuerpo de respuesta

Fuentes

Http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 1. http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

 7
Author: john,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-26 16:56:00

Ese es un post muy antiguo, pero me enfrenté a un problema similar y me gustaría compartir mi experiencia con ustedes.

Estoy construyendo arquitectura de microservicios con API rest. Tengo algunos servicios de rest GET, recopilan datos del sistema back-end basado en los parámetros de la solicitud.

Seguí los documentos de diseño de la API rest y envié HTTP 404 con un mensaje de error JSON perfecto al cliente cuando no había datos que se alinearan con las condiciones de consulta (por ejemplo, el registro cero fue elegido).

Cuando no había datos que enviar al cliente preparé un mensaje JSON perfecto con código de error interno, etc. para informar al cliente sobre la razón del "No encontrado" y se envió de vuelta al cliente con HTTP 404. Eso funciona bien.

Más tarde he creado una clase de cliente de API REST que es un ayudante fácil para ocultar el código relacionado con la comunicación HTTP y utilicé este ayudante todo el tiempo cuando llamé a mis API rest desde mi código.

PERO necesitaba escribir confundir código extra solo porque HTTP 404 tenía dos funciones diferentes:

  • el HTTP 404 real cuando la API rest no está disponible en la url dada, es lanzada por el servidor de aplicaciones o servidor web donde se ejecuta la aplicación API rest
  • el cliente también obtiene HTTP 404 cuando no hay datos en la base de datos basados en la condición where de la consulta.

Importante: Mi controlador de errores de la API rest captura todas las excepciones aparece en el servicio de back-end, lo que significa en caso de cualquier error, mi API rest siempre devuelve un mensaje JSON perfecto con los detalles del mensaje.

Esta es la 1a versión de mi método de ayuda de cliente que maneja las dos respuestas HTTP 404 diferentes:

public static String getSomething(final String uuid) {
    String serviceUrl = getServiceUrl();
    String path = "user/" + , uuid);
    String requestUrl = serviceUrl + path;
    String httpMethod = "GET";

    Response response = client
            .target(serviceUrl)
            .path(path)
            .request(ExtendedMediaType.APPLICATION_UTF8)
            .get();

    if (response.getStatus() == Response.Status.OK.getStatusCode()) {
        // HTTP 200
        return response.readEntity(String.class);
    } else {
        // confusing code comes here just because
        // I need to decide the type of HTTP 404...

        // trying to parse response body
        try {
            String responseBody = response.readEntity(String.class);
            ObjectMapper mapper = new ObjectMapper();
            ErrorInfo errorInfo = mapper.readValue(responseBody, ErrorInfo.class);

            // re-throw the original exception
            throw new MyException(errorInfo);

        } catch (IOException e) {
            // this is a real HTTP 404
            throw new ServiceUnavailableError(response, requestUrl, httpMethod);
        }

    // this exception will never be thrown
    throw new Exception("UNEXPECTED ERRORS, BETTER IF YOU DO NOT SEE IT IN THE LOG");
}

PERO , debido a que mi cliente Java o JavaScript puede recibir dos tipos de HTTP 404 de alguna manera necesito verificar el cuerpo de la respuesta en el caso de HTTP 404. Si puedo analizar el cuerpo de la respuesta, entonces estoy seguro de que recibí una respuesta donde no había datos para enviar de vuelta al cliente.

Si no puedo analizar la respuesta, eso significa que recuperé un HTTP 404 real del servidor web (no de la aplicación rest API).

Es muy confuso y la aplicación cliente siempre necesita hacer un análisis adicional para verificar la verdadera razón de HTTP 404.

Honestamente no me gusta esta solución. Es confuso, necesita agregar código adicional de mierda a los clientes todo el tiempo.

Así que en lugar de usar HTTP 404 en estos dos escenarios diferentes decidí que voy a hacer lo siguiente:

  • Ya no estoy usando HTTP 404 como código HTTP de respuesta en mi aplicación rest.
  • Voy a usar HTTP 204 (Sin contenido) en lugar de HTTP 404.

En ese caso el código del cliente puede ser más elegante:

public static String getString(final String processId, final String key) {
    String serviceUrl = getServiceUrl();
    String path = String.format("key/%s", key);
    String requestUrl = serviceUrl + path;
    String httpMethod = "GET";

    log(requestUrl);

    Response response = client
            .target(serviceUrl)
            .path(path)
            .request(ExtendedMediaType.APPLICATION_JSON_UTF8)
            .header(CustomHttpHeader.PROCESS_ID, processId)
            .get();

    if (response.getStatus() == Response.Status.OK.getStatusCode()) {
        return response.readEntity(String.class);
    } else {
        String body = response.readEntity(String.class);
        ObjectMapper mapper = new ObjectMapper();
        ErrorInfo errorInfo = mapper.readValue(body, ErrorInfo.class);
        throw new MyException(errorInfo);
    }

    throw new AnyServerError(response, requestUrl, httpMethod);
}

Creo que esto maneja mejor ese tema.

Si tiene alguna solución mejor, por favor compártala con nosotros.

 5
Author: zappee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-19 22:19:54

El Identificador Uniforme de recursos es un puntero único al recurso. Un URI de forma deficiente no apunta al recurso y, por lo tanto, realizar un GET on no devolverá un recurso. 404 significa que el servidor no ha encontrado nada que coincida con el URI de solicitud. Si pones el URI incorrecto o mal URI ese es tu problema y la razón por la que no llegaste a un recurso ya sea una página HTML o IMG.

 1
Author: suing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-06 13:10:32

Para este escenario HTTP 404 es el código de respuesta para la respuesta de la API REST Como 400, 401, 404, 422 entidad no procesable

Use el manejo de excepciones para verificar el mensaje de excepción completo.

try{
  // call the rest api
} catch(RestClientException e) {
     //process exception
     if(e instanceof HttpStatusCodeException){
        String responseText=((HttpStatusCodeException)e).getResponseBodyAsString();
         //now you have the response, construct json from it, and extract the errors
         System.out.println("Exception :" +responseText);
     }

}

Este bloque de excepción le da el mensaje apropiado lanzado por la API REST

 0
Author: Venkata Naresh Babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-04 12:19:27