it-swarm.com.de

REST API 404: Ungültiger URI oder fehlende Ressource?

Ich erstelle eine REST API, aber ich habe ein Problem festgestellt.

Es scheint, dass die gängige Praxis beim Entwerfen einer REST API darin besteht, dass eine 404 zurückgegeben wird, wenn die angeforderte Ressource nicht vorhanden ist.

Dies fügt mir jedoch unnötige Mehrdeutigkeiten hinzu. HTTP 404 wird traditionell mit einer schlechten URI assoziiert. Tatsächlich sagen wir also "Entweder sind Sie an der richtigen Stelle angekommen, aber dieser spezifische Datensatz existiert nicht, oder es gibt keinen solchen Ort im Internet! I bin mir wirklich nicht sicher welches ... "

Betrachten Sie den folgenden URI:

http://mywebsite/api/user/13

Wenn ich einen 404 zurück bekomme, ist das, weil Benutzer 13 nicht existiert? Oder liegt es daran, dass meine URL hätte sein sollen:

http://mywebsite/restapi/user/13

In der Vergangenheit habe ich gerade ein NULL-Ergebnis mit einem HTTP 200 OK - Antwortcode zurückgegeben, wenn der Datensatz nicht vorhanden ist. Es ist einfach und meiner Meinung nach sehr sauber, auch wenn es nicht unbedingt akzeptierte Praxis ist. Aber gibt es einen besseren Weg, dies zu tun?

182
Brian Lacy

404 ist nur der HTTP-Antwortcode. Darüber hinaus können Sie einen Antworttext und/oder andere Header mit einer aussagekräftigeren Fehlermeldung versehen, die den Entwicklern angezeigt wird.

82
Robert Levy

Verwenden 404 wenn die Ressource nicht existiert. Kehre nicht zurück 200 mit einem leeren Körper.

Dies ist vergleichbar mit undefined vs. leere Zeichenfolge (z. B. "") in der Programmierung. Obwohl sehr ähnlich, gibt es definitiv einen Unterschied.

404 bedeutet, dass an dieser URI nichts existiert (wie eine undefinierte Variable in der Programmierung). Zurück 200 mit einem leeren Körper bedeutet, dass dort etwas existiert und dass gerade etwas leer ist (wie ein leerer String in der Programmierung).

404 bedeutet nicht, dass es eine "schlechte URI" war. Es gibt spezielle HTTP-Codes, die für URI-Fehler vorgesehen sind (z. B. 414 Request-URI Too Long).

47
nategood

Wie bei den meisten Dingen "kommt es darauf an". Aber für mich ist Ihre Praxis nicht schlecht und widerspricht nicht der HTTP-Spezifikation per se. Lassen Sie uns jedoch einige Dinge klären.

Erstens sollten URIs undurchsichtig sein. Auch wenn sie für Menschen nicht undurchsichtig sind, sind sie für Maschinen undurchsichtig. Mit anderen Worten, der Unterschied zwischen http://mywebsite/api/user/13, http://mywebsite/restapi/user/13 Ist derselbe wie der Unterschied zwischen http://mywebsite/api/user/13 Und http://mywebsite/api/user/14, D. H. Nicht derselbe ist nicht derselbe Zeitraum. Ein 404 wäre also völlig angemessen für http://mywebsite/api/user/14 (Wenn es keinen solchen Benutzer gibt), aber nicht unbedingt die einzig angemessene Antwort.

Sie können auch eine leere 200-Antwort oder explizit eine 204-Antwort (ohne Inhalt) zurückgeben. Dies würde dem Kunden etwas anderes vermitteln. Dies würde bedeuten, dass die mit http://mywebsite/api/user/14 Gekennzeichnete Ressource keinen Inhalt hat oder im Wesentlichen nichts ist. Es bedeutet, dass es ist eine solche Ressource gibt. Dies bedeutet jedoch nicht unbedingt, dass Sie behaupten, dass ein Benutzer in einem Datenspeicher mit der ID 14 verbleibt. Dies ist Ihr privates Anliegen, nicht das Anliegen des Kunden, der die Anfrage gestellt hat. Wenn es also Sinn macht, Ihre Ressourcen auf diese Weise zu modellieren, fahren Sie fort.

Es gibt einige Sicherheitsrisiken, wenn Sie Ihren Kunden Informationen zur Verfügung stellen, die es ihnen erleichtern würden, legitime URIs zu erraten. Das Zurückgeben von 200 bei Fehlern anstelle von 404 kann dem Client einen Hinweis darauf geben, dass mindestens der Teil http://mywebsite/api/user Korrekt ist. Ein böswilliger Client könnte einfach weiterhin verschiedene Ganzzahlen testen. Aber für mich könnte ein böswilliger Client den Teil http://mywebsite/api/user Trotzdem erraten. Ein besseres Mittel wäre die Verwendung von UUIDs. d.h. http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 ist besser als http://mywebsite/api/user/14. Auf diese Weise können Sie Ihre Technik anwenden, um 200 zurückzukehren, ohne viel zu verraten.

17
jhericks

404 Not Found bedeutet technisch, dass uri momentan nicht map zu einer Ressource gehört. In Ihrem Beispiel interpretiere ich eine Anfrage an http://mywebsite/api/user/13, Die ein 404 zurückgibt, um zu implizieren, dass diese URL nie einer Ressource zugeordnet wurde. Für den Kunden sollte dies das Ende des Gesprächs sein.

Um Bedenken mit Mehrdeutigkeit auszuräumen, können Sie Ihre API durch Angabe anderer Antwortcodes erweitern. Angenommen, Sie möchten Clients erlauben, GET-Anforderungen mit der URL http://mywebsite/api/user/13 Auszustellen. Sie möchten mitteilen, dass Clients die kanonische URL http://mywebsite/restapi/user/13 Verwenden sollen. In diesem Fall können Sie eine permanente Weiterleitung in Betracht ziehen, indem Sie 301 dauerhaft verschoben zurückgeben und die kanonische URL im Speicherort Header der Antwort angeben. Dies teilt dem Client mit, dass er für zukünftige Anforderungen die kanonische URL verwenden soll.

11

Im Wesentlichen klingt es so, als ob die Antwort davon abhängen könnte, wie die Anfrage gebildet wird.

Wenn die angeforderte Ressource gemäß einer Anforderung an http://mywebsite/restapi/user/13 Teil des URI ist und Benutzer 13 nicht vorhanden ist, ist ein 404 wahrscheinlich angemessen und intuitiv, da der URI für einen nicht vorhandenen Benutzer/eine nicht vorhandene Entität/ein nicht vorhandenes Dokument steht /usw. Gleiches gilt für die sicherere Technik mit einem GUID http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 Und dem obigen api/restapi-Argument.

Wenn jedoch die angeforderte Ressourcen-ID im Anforderungsheader enthalten ist [enthalten Sie Ihr eigenes Beispiel] oder in der Tat in der URI als Parameter, z. B. http://mywebsite/restapi/user/?UID=13, Dann ist die URI immer noch korrekt (weil das Konzept von a USER beendet sich um http://mywebsite/restapi/user/); und daher ist zu erwarten, dass die Antwort vernünftigerweise 200 (mit einer entsprechend ausführlichen Nachricht) ist, da der als 13 bekannte spezifische Benutzer nicht existiert, der URI jedoch. Auf diese Weise sagen wir, dass der URI gut ist, aber die Datenanforderung keinen Inhalt hat.

Persönlich fühlt sich ein 200er immer noch nicht richtig an (obwohl ich es zuvor argumentiert habe). Ein 200-Antwortcode (ohne ausführliche Antwort) kann dazu führen, dass ein Problem nicht untersucht wird, wenn beispielsweise eine falsche ID gesendet wird.

Ein besserer Ansatz wäre, eine Antwort 204 - No Content Zu senden. Dies entspricht der Beschreibung von w3c. * Der Server hat die Anforderung erfüllt, muss jedoch keinen Entity-Body zurückgeben und möchte möglicherweise aktualisierte Metainformationen zurückgeben. * 1 Die Verwirrung wird meiner Meinung nach durch den Wikipedia-Eintrag verursacht, der angibt, dass 204 Kein Inhalt - Der Server hat die Anforderung erfolgreich verarbeitet, gibt jedoch keinen Inhalt zurück. Wird normalerweise als Antwort auf eine erfolgreiche Löschanforderung verwendet . Der letzte Satz ist höchst umstritten. Betrachten Sie die Situation ohne diesen Satz und die Lösung ist einfach - senden Sie einfach eine 204, wenn die Entität nicht existiert. Es gibt sogar ein Argument für die Rückgabe einer 204 anstelle einer 404, die Anfrage wurde verarbeitet und es wurde kein Inhalt zurückgegeben! Beachten Sie jedoch, dass 204 keine Inhalte im Antworttext zulassen

Quellen

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

8
john

Dieser alte, aber ausgezeichnete Artikel ... http://www.infoq.com/articles/webber-rest-workflow sagt dies darüber aus ...

404 Not Found (Nicht gefunden) - Der Service ist viel zu faul (oder zu sicher), um einen wirklichen Grund für das Fehlschlagen unserer Anfrage anzugeben.

7

Das ist ein sehr alter Beitrag, aber ich hatte ein ähnliches Problem und möchte meine Erfahrungen mit euch teilen.

Ich baue eine Microservice-Architektur mit Rest-APIs auf. Ich habe einige Rest-GET-Dienste, die Daten vom Back-End-System basierend auf den Anforderungsparametern sammeln.

Ich verfolgte die restlichen API-Designdokumente und schickte HTTP 404 mit einer perfekten JSON-Fehlermeldung an den Client zurück, wenn keine Daten vorhanden waren, die mit den Abfragebedingungen übereinstimmen (zum Beispiel wurde kein Datensatz ausgewählt).

Wenn keine Daten zum Client zurückgesendet werden konnten, erstellte ich eine perfekte JSON-Nachricht mit internem Fehlercode usw., um den Client über den Grund für "Nicht gefunden" zu informieren, und sie wurde mit HTTP 404 an den Client zurückgesendet funktioniert gut.

Später habe ich eine Rest-API-Client-Klasse erstellt, die ein einfacher Helfer ist, um den Code für die HTTP-Kommunikation auszublenden, und ich habe diesen Helfer die ganze Zeit verwendet, als ich meine Rest-APIs über meinen Code aufgerufen habe.

ABER ich musste verwirrenden zusätzlichen Code schreiben, nur weil HTTP 404 zwei verschiedene Funktionen hatte:

  • wenn die Rest-API in der angegebenen URL nicht verfügbar ist, wird sie vom Anwendungsserver oder Webserver ausgelöst, auf dem die Rest-API-Anwendung ausgeführt wird
  • der Client erhält auch HTTP 404 zurück, wenn keine Daten in der Datenbank vorhanden sind, basierend auf der WHERE-Bedingung der Abfrage.

Wichtig: Die Fehlerbehandlungsroutine für die Rest-API erfasst alle Ausnahmen, die im Back-End-Service angezeigt werden. Dies bedeutet, dass meine Rest-API im Fehlerfall immer eine perfekte JSON-Nachricht mit den Nachrichtendetails zurückgibt.

Dies ist die erste Version meiner Client-Hilfemethode, die die beiden unterschiedlichen HTTP 404-Antworten verarbeitet:

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");
}

ABER , weil mein Java oder JavaScript-Client zwei Arten von HTTP 404 empfangen kann Antwort im Fall von HTTP 404. Wenn ich den Antworttext analysieren kann, habe ich sicher eine Antwort erhalten, bei der keine Daten zum Client zurückgesendet werden konnten.

Wenn ich die Antwort nicht analysieren kann, bedeutet dies, dass ich vom Webserver (nicht von der Rest-API-Anwendung) ein echtes HTTP 404 zurückerhalten habe.

Dies ist so verwirrend, dass die Client-Anwendung immer zusätzliche Parsing-Vorgänge ausführen muss, um den tatsächlichen Grund für HTTP 404 zu ermitteln.

Ehrlich gesagt mag ich diese Lösung nicht. Es ist verwirrend, den Kunden ständig zusätzlichen Bullshit-Code hinzufügen zu müssen.

Anstatt HTTP 404 in diesen beiden verschiedenen Szenarien zu verwenden, habe ich beschlossen, Folgendes zu tun:

  • Ich verwende HTTP 404 nicht mehr als Antwort-HTTP-Code in meiner Restanwendung.
  • Ich werde HTTP 204 (kein Inhalt) anstelle von HTTP 404 verwenden.

In diesem Fall kann der Client-Code eleganter sein:

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);
}

Ich denke, das regelt das Problem besser.

Wenn Sie eine bessere Lösung haben, teilen Sie sie uns bitte mit.

6
zappee

Der Uniform Resource Identifier ist ein eindeutiger Zeiger auf die Ressource. Ein schlecht geformter URI zeigt nicht auf die Ressource und daher wird durch Ausführen eines GET keine Ressource zurückgegeben. 404 bedeutet, dass der Server nichts gefunden hat, was mit dem Anforderungs-URI übereinstimmt. Wenn Sie den falschen oder den falschen URI eingegeben haben, ist dies Ihr Problem und der Grund, warum Sie nicht zu einer Ressource gelangt sind, sei es eine HTML-Seite oder ein IMG.

1
suing

In diesem Szenario ist HTTP 404 der Antwortcode für die Antwort von der REST API Wie 400, 401, 404, 422 nicht verarbeitbare Entität

verwenden Sie die Ausnahmebehandlung, um die vollständige Ausnahmemeldung zu überprüfen.

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);
     }

}

Dieser Ausnahmeblock gibt Ihnen die richtige Nachricht, die von der REST API ausgegeben wird

0