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

219

Ich erstelle eine REST-API, bin jedoch auf ein Problem gestoßen.

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

Für mich führt dies jedoch zu unnötiger Mehrdeutigkeit. HTTP 404 ist traditioneller mit einem schlechten URI verbunden. Tatsächlich sagen wir also: "Entweder bist du am richtigen Ort, aber dieser spezifische Datensatz existiert nicht, oder es gibt keinen solchen Ort im Internet! Ich bin mir wirklich nicht sicher, welcher ..."

Betrachten Sie den folgenden URI:

http://mywebsite/api/user/13

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

http://mywebsite/restapi/user/13

In der Vergangenheit habe ich gerade ein NULL-Ergebnis mit einem HTTP 200 OKAntwortcode 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?

Brian Lacy
quelle
Wahrscheinlich ein Duplikat. stackoverflow.com/questions/3821663/…
Spencer Kormos
7
Die andere Frage scheint sich auf URI-Abfragezeichenfolgenformate zu beziehen. Die Diskussion über 404 dort reicht nicht aus, um meine Frage zu beantworten, ob es einen angemesseneren oder nützlicheren Weg gibt, um festzustellen, was ein 404 tatsächlich bedeutet. Ich habe das vor dem Posten überprüft.
Brian Lacy
Ist es normal, wenn Browser Concole die Fehler 404 enthält? Wenn ich regelmäßige Operationen mit korrekter URL mache, aber Ressource nicht gefunden.
Vasiliy Mazhekin
3
404 zeigt keinen fehlerhaften URI an, sondern eine nicht gefundene Ressource. Dies kann daran liegen, dass kein Benutzer '13' vorhanden ist, oder daran, dass keine Ressource / mywebsite / api vorhanden ist.
ChrisV

Antworten:

101

404 ist nur der HTTP-Antwortcode. Darüber hinaus können Sie einem Antworttext und / oder anderen Headern eine aussagekräftigere Fehlermeldung bereitstellen, die Entwickler sehen werden.

Robert Levy
quelle
7
Das macht Sinn. Ich muss mich jedoch fragen, ob die Rückgabe des 404 überhaupt einen Vorteil gegenüber der Rückgabe eines 200 mit einer Nullantwort bringt.
Brian Lacy
15
Wenn Sie eine 200 mit einer Null zurückgeben, gehen Sie gegen die HTTP-Spezifikation vor. Sie können dies tun, aber dann wird Ihre API die REST-Einschränkung "Uniformed Interface" nicht einhalten.
Klage am
5
... und Ihr Antworttext sollte Hyperlinks zu gültigen URIs enthalten. Abgesehen von der Root-URI und möglicherweise ein oder zwei Lesezeichen sollten Ihre Clients immer den vom Server angegebenen Links folgen. Dann müssen Sie keine detaillierte Semantik darüber erfinden, wie sie sich entschieden haben, außerhalb des Systems zu arbeiten.
Fumanchu
@DarrylHebbes Was meinst du damit? Ich kann eine Anfrage stellen und den vollständigen Inhalt der Antwort auf der Registerkarte "Netzwerk" der Chrome-Entwicklerkonsole anzeigen.
Jaapz
59

Verwenden Sie 404diese Option, wenn die Ressource nicht vorhanden ist. Kehre nicht 200mit leerem Körper zurück.

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

404bedeutet, dass an diesem URI nichts vorhanden ist (wie eine undefinierte Variable in der Programmierung). Die Rückkehr 200mit einem leeren Körper bedeutet, dass dort etwas existiert und dass gerade etwas leer ist (wie eine leere Zeichenfolge in der Programmierung).

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

nategood
quelle
1
Hey, ich denke du bist vielleicht auf etwas. Wäre es nicht sinnvoller, eine der "41" zurückzugeben? Fehler, wenn ein Problem mit der angeforderten Ressource vorliegt? Beispiel: 410 Gone bedeutet "Die angeforderte Ressource ist auf dem Server nicht mehr verfügbar und es ist keine Weiterleitungsadresse bekannt." - (Siehe w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.11 )
Brian Lacy
In der Ressource, auf die ich oben verwiesen habe, heißt es außerdem: "Wenn der Server nicht weiß oder keine Möglichkeit hat, festzustellen, ob die Bedingung dauerhaft ist oder nicht, sollte stattdessen der Statuscode 404 (nicht gefunden) verwendet werden." Vielleicht ist das auch nicht unbedingt die beste Option.
Brian Lacy
2
Ich denke nicht, dass einer der 41x-Fehler für Ihren Anwendungsfall geeignet ist. Ich mag den Vergleich mit undefinierten und leeren Zeichenfolgen, was eine präzisere Version meines Punktes in meiner Antwort ist. Es gibt einen Unterschied, aber das bedeutet nicht, dass eine leere Zeichenfolge ein Fehler ist. Um die Analogie zu erweitern: Sie könnten eine Methode haben String getName(), die eine Implementierung wie diese hat : return this.name == null ? "" : this.name. Das ist nicht falsch , wenn Sie der Kunde wissen wollen , dass this.nameist null.
Jhericks
1
404 ist immer noch die am besten geeignete Option. Sie können (und werden dazu ermutigt) den Text dieser 404-Antwort verwenden, um den Benutzer / Client über bestimmte Details zum Empfang des Fehlers zu informieren. Siehe: stackoverflow.com/a/9999335/105484 . In Ihrem Fall möchten Sie diesen Text möglicherweise verwenden, um dem Benutzer vorzuschlagen, dass er seinen URI neu formatiert, damit er wie / restapi / user / USER_ID
nategood
Ok, ich kann hier einige gute Punkte sehen, aber 4XX sind Fehlercodes. Wie ist das eine Fehlersituation? Wie kann der Client verhindern, dass 404 auftritt?
Krzysztof Kubicki
20

Wie bei den meisten Dingen kommt es darauf an. Aber für mich ist Ihre Praxis nicht schlecht und widerspricht nicht der HTTP-Spezifikation an sich . 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/13ist der gleiche wie der Unterschied zwischen http://mywebsite/api/user/13und http://mywebsite/api/user/14dh nicht der gleiche ist nicht der gleiche Zeitraum. Ein 404 wäre also völlig geeignet für http://mywebsite/api/user/14(wenn es keinen solchen Benutzer gibt), aber nicht unbedingt die einzig geeignete Antwort.

Sie können auch eine leere 200-Antwort oder expliziter eine 204-Antwort (kein Inhalt) zurückgeben. Dies würde dem Kunden etwas anderes vermitteln. Dies würde bedeuten, dass die durch identifizierte Ressource http://mywebsite/api/user/14keinen Inhalt hat oder im Wesentlichen nichts ist. Es bedeutet, dass es 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 stellt. Wenn es also sinnvoll ist, Ihre Ressourcen auf diese Weise zu modellieren, fahren Sie fort.

Die Bereitstellung von Informationen für Ihre Kunden hat einige Sicherheitsaspekte, die es ihnen erleichtern würden, legitime URIs zu erraten. Die Rückgabe einer 200 bei Fehlern anstelle einer 404 kann dem Kunden einen Hinweis geben, dass zumindest der http://mywebsite/api/userTeil korrekt ist. Ein böswilliger Client könnte einfach weiterhin verschiedene Ganzzahlen ausprobieren. Aber für mich könnte ein böswilliger Kunde das http://mywebsite/api/userTeil trotzdem erraten . Ein besseres Mittel wäre die Verwendung von UUIDs. dh http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66ist besser als http://mywebsite/api/user/14. Auf diese Weise können Sie Ihre Technik anwenden, 200er zurückzugeben, ohne viel zu verraten.

Jhericks
quelle
1
Dies ist die Lösung, die ich gewählt und mit einem 204 anstelle eines 404 verwendet habe. Für mich bedeutet 204 "Ich habe Ihren Code gefunden, aber keine Ergebnisse gefunden" und 404 bedeutet "Ich konnte keinen Code zum Ausführen finden" der falsche Weg? "
Matt Sanders
11

404 Not Found technisch bedeutet , dass uri derzeit keine Karte auf eine Ressource. In Ihrem Beispiel interpretiere ich eine Anfrage, http://mywebsite/api/user/13die eine 404 zurückgibt, um zu implizieren, dass diese URL niemals einer Ressource zugeordnet wurde. Für den Kunden sollte dies das Ende des Gesprächs sein.

Um Bedenken mit Mehrdeutigkeiten auszuräumen, können Sie Ihre API verbessern, indem Sie andere Antwortcodes bereitstellen. Angenommen, Sie möchten Clients erlauben, GET-Anforderungen mit der URL zu versehen http://mywebsite/api/user/13, und Sie möchten mitteilen, dass Clients die kanonische URL verwenden sollen http://mywebsite/restapi/user/13. In diesem Fall sollten Sie eine permanente Weiterleitung in Betracht ziehen, indem Sie eine 301 Moved Permanent zurückgeben und die kanonische URL im Location- Header der Antwort angeben. Dies teilt dem Client mit, dass er für zukünftige Anfragen die kanonische URL verwenden soll.

Ralph Allan Rice
quelle
10

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 den http://mywebsite/restapi/user/13Benutzer 13 Teil des URI ist und der 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 / etc. Repräsentant ist. Gleiches gilt für die sicherere Technik mit einer GUID http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66und dem obigen Argument api / restapi.

Wenn jedoch die angeforderte Ressourcen-ID im Anforderungsheader enthalten wäre [geben Sie Ihr eigenes Beispiel an] oder tatsächlich in der URI als Parameter, z. B. http://mywebsite/restapi/user/?UID=13dann wäre die URI immer noch korrekt (da das Konzept eines USER bei beendet wird http://mywebsite/restapi/user/). und daher könnte vernünftigerweise erwartet werden, dass die Antwort 200 ist (mit einer entsprechend ausführlichen Nachricht), da der spezifische Benutzer, der als 13 bekannt ist, nicht existiert, aber der URI. Auf diese Weise sagen wir, dass der URI gut ist, aber die Anforderung von Daten keinen Inhalt hat.

Persönlich fühlt sich eine 200 immer noch nicht richtig an (obwohl ich zuvor argumentiert habe, dass dies der Fall ist). 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 204 - No ContentAntwort 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 mit der Angabe 204 No Content verursacht - 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 sehr 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 eines 204 anstelle eines 404, die Anfrage wurde verarbeitet und es wurde kein Inhalt zurückgegeben! Bitte 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

John
quelle
9

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

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

Ich habe die restlichen API-Entwurfsdokumente befolgt und HTTP 404 mit einer perfekten JSON-Fehlermeldung an den Client zurückgesendet, wenn keine Daten vorhanden waren, die mit den Abfragebedingungen übereinstimmen (z. B. wurde der Datensatz Null ausgewählt).

Wenn keine Daten an den Client zurückgesendet werden konnten, habe ich eine perfekte JSON-Nachricht mit internem Fehlercode usw. vorbereitet, 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 HTTP-Kommunikationscode auszublenden, und ich habe diesen Helfer die ganze Zeit verwendet, als ich meine Rest-APIs aus meinem Code heraus 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: Mein Rest-API-Fehlerbehandler fängt alle Ausnahmen ab, die im Back-End-Service angezeigt werden. Im Fehlerfall gibt meine Rest-API immer eine perfekte JSON-Nachricht mit den Nachrichtendetails zurück.

Dies ist die erste Version meiner Client-Hilfsmethode, die die zwei verschiedenen 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 irgendwie zwei Arten von HTTP 404 empfangen kann, muss ich im Fall von HTTP 404 den Text der Antwort überprüfen. Wenn ich den Antworttext analysieren kann, bin ich sicher, dass ich eine Antwort zurückbekommen habe, wo sie war Keine Daten zum Zurücksenden an den Client.

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

Es ist so verwirrend und die Client-Anwendung muss immer zusätzliche Analysen durchführen, um den wahren Grund von HTTP 404 zu überprüfen.

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

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 Clientcode 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 behandelt dieses Problem besser.

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

Zappee
quelle
Apache HttpClient-Methoden lösen bei einer 204-Antwort keine Ausnahme aus. Wenn Ihr Client nur Geschäftsobjekte (Modelle) beantwortet, gibt dies null zurück. Funktioniert, ist für Endbenutzer jedoch schwierig, die Situation zu erkennen.
Chrisinmtown
Es ist alles gut, aber eine Frage ist: Wie oft schreibst du if-Anweisungen für den 404? Und was wäre das? Wenn Sie dagegen die API aufrufen, die die mögliche 404 mit dem Fehler json im Inneren definiert, können Sie dies nur für diesen Fall behandeln.
Max
zappee Ich stimme dir zu. Ich habe einen Dienst, der Daten zurückgibt. Es gibt jedoch Situationen, in denen die Daten beschädigt sind. Die Anforderungs-URL ist korrekt (also keine 404), aber es handelt sich nicht wirklich um einen logischen Fehler (500), sodass 204 am besten geeignet erscheint. Es ist wirklich ärgerlich über das Fehlen einer Nachrichtenkörpersache. Obwohl ich wohl einen Grund in einen Header einfügen könnte.
cs94njw
6

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

404 Nicht gefunden - Der Service ist viel zu faul (oder sicher), um uns einen wirklichen Grund zu nennen, warum unsere Anfrage fehlgeschlagen ist, aber aus welchem ​​Grund auch immer, wir müssen uns darum kümmern.

Michael Dausmann
quelle
1

Der Uniform Resource Identifier ist ein eindeutiger Zeiger auf die Ressource. Ein URI mit schlechter Form 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, das mit dem Request-URI übereinstimmt. Wenn Sie den falschen oder einen 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.

verklagen
quelle
0

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

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 ausgelöst wird

Venkata Naresh Babu
quelle