wake-up-neo.com

HTTP-Antwortcode für POST, wenn die Ressource bereits vorhanden ist

Ich baue einen Server, auf dem Clients Objekte speichern können. Diese Objekte werden vollständig clientseitig erstellt und enthalten Objekt-IDs, die für die gesamte Lebensdauer des Objekts permanent sind.

Ich habe die API so definiert, dass Clients Objekte mit PUT erstellen oder ändern können:

PUT /objects/{id} HTTP/1.1
...

{json representation of the object}

Die {ID} ist die Objekt-ID und somit Teil der Anforderungs-URI.

Jetzt überlege ich mir auch, Clients zu erlauben, das Objekt mit POST zu erstellen:

POST /objects/ HTTP/1.1
...

{json representation of the object, including ID}

Da POST als "Anhängen" -Operation gedacht ist, bin ich mir nicht sicher, was zu tun ist, falls das Objekt bereits vorhanden ist. Soll ich die Anforderung als Änderungsanforderung behandeln oder einen Fehlercode zurückgeben (welcher)?

720
vmj

Mein Gefühl ist 409 Conflict am angemessensten, aber in freier Wildbahn natürlich selten zu sehen:

Die Anforderung konnte aufgrund eines Konflikts mit dem aktuellen Status der Ressource nicht abgeschlossen werden. Dieser Code ist nur in Situationen zulässig, in denen erwartet wird, dass der Benutzer den Konflikt möglicherweise lösen und die Anforderung erneut senden kann. Der Antworttext SOLLTE genügend Informationen enthalten, damit der Benutzer die Ursache des Konflikts erkennen kann. Im Idealfall würde die Antwortentität genügend Informationen enthalten, damit der Benutzer oder Benutzeragent das Problem beheben kann. Dies ist jedoch möglicherweise nicht möglich und nicht erforderlich.

Konflikte treten am wahrscheinlichsten als Reaktion auf eine PUT-Anforderung auf. Wenn beispielsweise die Versionierung verwendet wird und die Entität, die PUT ist, Änderungen an einer Ressource enthält, die mit den von einer früheren (Drittanbieter-) Anforderung vorgenommenen Konflikten in Konflikt stehen, verwendet der Server möglicherweise die Antwort 409, um anzuzeigen, dass die Anforderung nicht abgeschlossen werden kann . In diesem Fall enthält die Antwortentität wahrscheinlich eine Liste der Unterschiede zwischen den beiden Versionen in einem Format, das durch den Inhaltstyp der Antwort definiert wird.

896
Wrikken

Gemäß RFC 7231 KANN ein 303 See Other verwendet werden Wenn das Ergebnis der Verarbeitung a POST entspricht einer Darstellung einer vorhandenen Ressource .

80
Nullius

Persönlich gehe ich mit der WebDAV-Erweiterung 422 Unprocessable Entity.

Gemäß RFC 4918

Der 422 Unprocessable Entity -Statuscode bedeutet, dass der Server den Inhaltstyp der Anforderungsentität versteht (daher ist ein 415 Unsupported Media Type -Statuscode ungeeignet) und die Syntax der Anforderungsentität korrekt ist (daher ein 400 Bad Request). Statuscode ist unangemessen), konnte die enthaltenen Anweisungen jedoch nicht verarbeiten.

76
Gareth

Vielleicht zu spät zum Spiel, aber ich bin auf dieses Semantikproblem gestoßen, als ich versucht habe, eine REST -API zu erstellen.

Um die Antwort von Wrikken ein wenig zu erläutern, könnten Sie je nach Situation entweder 409 Conflict oder 403 Forbidden verwenden - kurz gesagt: Verwenden Sie einen 403-Fehler, wenn der Benutzer absolut nichts tun kann, um den Konflikt zu lösen und abzuschließen die Anfrage (z. B. können sie keine DELETE Anfrage senden, um die Ressource explizit zu entfernen), oder verwenden Sie 409, wenn möglicherweise etwas getan werden könnte.

10.4.4 403 Verboten

Der Server hat die Anfrage verstanden, lehnt sie jedoch ab. Die Autorisierung hilft nicht und die Anfrage SOLLTE NICHT wiederholt werden. Wenn die Anforderungsmethode nicht HEAD war und der Server veröffentlichen möchte, warum die Anforderung nicht erfüllt wurde, SOLLTE er den Grund für die Ablehnung in der Entität beschreiben. Wenn der Server diese Informationen dem Client nicht zur Verfügung stellen möchte, kann stattdessen der Statuscode 404 (Not Found) verwendet werden.

Heutzutage sagt jemand "403" und es kommt ein Berechtigungs- oder Authentifizierungsproblem in den Sinn, aber die Spezifikation besagt, dass es im Grunde genommen der Server ist, der dem Client mitteilt, dass er es nicht tun wird, frag ihn nicht noch einmal und hier ist, warum der Client es nicht sollte nicht.

Wie für PUT vs. POST... POST sollte verwendet werden, um eine neue Instanz einer Ressource zu erstellen, wenn der Benutzer keine Möglichkeit hat, einen Bezeichner für die Ressource zu erstellen, oder nicht . PUT wird verwendet, wenn die Identität der Ressource bekannt ist.

9,6 PUT

...

Der grundlegende Unterschied zwischen den Anforderungen POST und PUT spiegelt sich in der unterschiedlichen Bedeutung der Anforderungs-URI wider. Der URI in einer POST -Anforderung gibt die Ressource an, die die eingeschlossene Entität verarbeiten soll. Diese Ressource kann ein datenakzeptierender Prozess, ein Gateway zu einem anderen Protokoll oder eine separate Entität sein, die Anmerkungen akzeptiert. Im Gegensatz dazu identifiziert der URI in einer PUT-Anforderung die Entität, die der Anforderung beigefügt ist - der Benutzeragent weiß, welche URI beabsichtigt ist, und der Server darf NICHT versuchen, die Anforderung auf eine andere Ressource anzuwenden. Wenn der Server wünscht, dass die Anforderung auf einen anderen URI angewendet wird,

es MUSS eine 301-Antwort (dauerhaft verschoben) senden; Das Benutzerprogramm KANN dann selbst entscheiden, ob die Anforderung umgeleitet werden soll oder nicht.

25
p0lar_bear

"302 gefunden" klingt für mich logisch. Und das RFC 2616 besagt, dass es für andere Anfragen als GET und HEAD beantwortet werden KANN (und dies schließt sicherlich POST ein)

Der Besucher wird jedoch weiterhin auf diese URL weitergeleitet, um diese "Gefunden" -Ressource vom RFC abzurufen. Um direkt zur tatsächlichen "Gefunden" -URL zu gelangen, sollte "303 See Other" verwendet werden. Dies ist sinnvoll, erzwingt jedoch einen weiteren Aufruf, um die folgende URL abzurufen. Auf der guten Seite ist dieses GET zwischenspeicherbar.

Ich denke, dass ich "303 See Other" verwenden würde. Ich weiß nicht, ob ich mit dem "Ding" antworten kann, das sich im Körper befindet, aber ich möchte dies tun, um eine Rundreise zum Server zu sparen.

UPDATE: Nach dem erneuten Lesen des RFC denke ich immer noch, dass ein nicht vorhanden ist Der Code "4XX + 303 Found" sollte korrekt sein. Der "409 Conflict" ist jedoch der beste vorhandene Antwortcode (wie von @ Wrikken angegeben), einschließlich eines Location-Headers, der auf die vorhandene Ressource verweist.

13
alanjds

Was ist mit der Rückgabe eines 418?

Da der Client darum bittet, eine Entität beizubehalten, die bereits auf dem Server vorhanden ist, wird der Server schließlich wütend und denkt, dass er eine Teekanne ist, und gibt Folgendes zurück: 418 I'm a teapot.

Verweise:

13
рüффп

Es geht um Kontext und darum, wer für Duplikate in Anfragen verantwortlich ist (Server oder Client oder beide)

Wenn der Server nur auf das Duplikat zeigt, sehen Sie sich 4xx an:

  • 400 Bad Request - wenn der Server die Anforderung nicht verarbeitet, weil ein offensichtlicher Clientfehler vorliegt
  • 409 Konflikt - Wenn der Server die Anforderung nicht verarbeitet, der Grund dafür jedoch nicht der Fehler des Clients ist
  • ...

Schauen Sie sich für implizite Behandlung von Duplikaten 2XX an:

  • 200 OK
  • 201 Erstellt
  • ...

wenn erwartet wird, dass der Server etwas zurückgibt , schauen Sie sich 3XX an:

  • 302 gefunden
  • 303 Siehe Sonstiges
  • ...

wenn der Server auf die vorhandene Ressource verweisen kann, bedeutet dies eine Umleitung.

Wenn das oben Genannte nicht ausreicht, empfiehlt es sich immer, eine Fehlermeldung im Hauptteil der Antwort vorzubereiten.

12

Ich denke nicht, dass Sie das tun sollten.

Wie Sie wissen, dient das POST zum Ändern der Sammlung und zum ERSTELLEN eines neuen Elements. Wenn Sie also die ID senden (ich denke, es ist keine gute Idee), sollten Sie die Sammlung ändern, d. H. Das Element ändern, aber es ist verwirrend.

Verwenden Sie diese Option, um einen Artikel ohne ID hinzuzufügen. Es ist die beste Praxis.

Wenn Sie eine UNIQUE-Einschränkung (nicht die ID) erfassen möchten, können Sie wie in PUT-Anforderungen auf 409 antworten. Aber nicht die ID.

9
Alfonso Tienda

Ich denke, für REST muss man nur eine Entscheidung über das Verhalten für das jeweilige System treffen. In diesem Fall ist die "richtige" Antwort eine der hier gegebenen Antworten. Wenn Sie möchten, dass die Anforderung angehalten wird und sich so verhält, als ob der Client einen Fehler gemacht hat, den er beheben muss, bevor Sie fortfahren, verwenden Sie 409. Wenn der Konflikt wirklich nicht so wichtig ist und die Anforderung am Laufen halten möchte, antworten Sie, indem Sie die umleiten Client zu der Entität, die gefunden wurde. Ich denke, richtige REST APIs sollten nach einem POST sowieso den GET-Endpunkt für diese Ressource umleiten (oder zumindest den Standortheader bereitstellen), damit dieses Verhalten eine konsistente Erfahrung liefert.

BEARBEITEN: Es ist auch erwähnenswert, dass Sie einen PUT in Betracht ziehen sollten, da Sie die ID angeben. Dann ist das Verhalten einfach: "Es ist mir egal, was gerade da ist, leg das Ding dort ab." Das heißt, wenn nichts da ist, wird es erschaffen. Wenn etwas da ist, wird es ersetzt. Ich denke, ein POST ist geeigneter, wenn der Server diese ID verwaltet. Die Trennung der beiden Konzepte zeigt im Grunde, wie man damit umgeht (dh PUT ist idempotent, so dass es immer funktionieren sollte, solange die Nutzdaten validiert werden, POST erstellt immer, wenn also eine Kollision von IDs vorliegt, dann a 409 würde diesen Konflikt beschreiben).

6
Sinaesthetic

Ich würde mit 422 Unprocessable Entity gehen, der verwendet wird, wenn eine Anfrage ungültig ist, das Problem jedoch nicht in Syntax oder Authentifizierung vorliegt.

Als Argument gegen andere Antworten würde die Verwendung eines anderen als 4xx-Fehlercodes bedeuten, dass es sich nicht um einen Clientfehler handelt, und dies ist offensichtlich der Fall. Die Verwendung eines nicht -4xx -Fehlercodes zur Darstellung eines Clientfehlers ist überhaupt nicht sinnvoll.

Anscheinend ist 409 Conflict die häufigste Antwort hier, aber laut Spezifikation impliziert dies, dass die Ressource bereits vorhanden ist und die neuen Daten, die Sie darauf anwenden, nicht mit ihrem aktuellen Status kompatibel sind. Wenn Sie eine POST -Anforderung senden, beispielsweise mit einem bereits belegten Benutzernamen, besteht kein Konflikt mit der Zielressource, da die Zielressource noch nicht gebucht wurde. Dies ist ein Fehler speziell für die Versionskontrolle, wenn ein Konflikt zwischen der Version der gespeicherten Ressource und der Version der angeforderten Ressource besteht. Dies ist beispielsweise dann sehr nützlich, wenn der Client eine alte Version der Ressource zwischengespeichert hat und eine Anforderung sendet, die auf dieser falschen Version basiert und nicht mehr unter bestimmten Bedingungen gültig ist. "In diesem Fall würde die Antwortdarstellung wahrscheinlich Informationen enthalten, die zum Zusammenführen der Unterschiede basierend auf dem Revisionsverlauf nützlich sind." Die Anforderung, einen anderen Benutzer mit diesem Benutzernamen zu erstellen, ist nur nicht verarbeitbar und hat nichts mit Versionskontrolle zu tun.

Für den Datensatz ist 422 auch der Statuscode, den GitHub verwendet, wenn Sie versuchen, ein Repository anhand eines bereits verwendeten Namens zu erstellen.

5
Grant Gryczan

Eine weitere mögliche Behandlung ist schließlich die Verwendung von PATCH. Ein PATCH ist als etwas definiert, das den internen Status ändert und nicht auf das Anhängen beschränkt ist.

PATCH würde das Problem lösen, indem Sie bereits vorhandene Elemente aktualisieren können. Siehe: RFC 5789: PATCH

4
Martin Kersten

Warum nicht ein 202 Akzeptiert ? Es ist eine OK-Anfrage (200s), es gab per se keine Client-Fehler (400s).

Von 10 Statuscode-Definitionen :

"202 Accepted. Die Anfrage wurde zur Verarbeitung angenommen, aber die Verarbeitung wurde nicht abgeschlossen."

... weil es nicht ausgefüllt werden musste, weil es bereits existierte. Der Kunde weiß nicht, dass es das schon gibt, er hat nichts falsch gemacht.

Ich möchte eine 202 werfen und ähnliche Inhalte zurückgeben, wie sie ein GET /{resource}/{id} zurückgegeben hätte.

4

Was ist mit 208 - http://httpstatusdogs.com/208-already-reported ? Ist das eine Option?

Meiner Meinung nach sollte kein Fehler ausgelöst werden, wenn das Einzige eine Wiederholungsressource ist. Immerhin gibt es weder auf der Client- noch auf der Serverseite einen Fehler.

2

Ich bin auf diese Frage gestoßen, als ich nach dem richtigen Code für doppelte Datensätze gesucht habe.

Verzeihen Sie meine Unwissenheit, aber ich verstehe nicht, warum alle den Code "300" ignorieren, der eindeutig "Multiple Choice" oder "Ambiguous" sagt.

Meiner Meinung nach ist dies der perfekte Code, um ein nicht standardisiertes oder ein bestimmtes System für Ihren eigenen Gebrauch zu erstellen. Ich könnte mich auch irren!

https://tools.ietf.org/html/rfc7231#section-6.4.1

2
Hitin

Eher ist es 400 Bad Request

6.5.1. 400 Bad Request


Der Statuscode 400 (Bad Request) gibt an, dass der Server die Anforderung aufgrund eines als Clientfehler wahrgenommenen Fehlers (z. B. fehlerhafte Anforderungssyntax, ungültige Anforderungsnachrichten oder irreführende Anforderung) nicht verarbeiten kann oder wird Routing).

Da die Anforderung einen doppelten Wert enthält (Wert, der bereits vorhanden ist), kann dies als Clientfehler angesehen werden. Die Anforderung muss vor dem nächsten Versuch geändert werden.
Unter Berücksichtigung dieser Fakten können wir als HTTP STATUS 400 Bad Request schließen.

2
Mohammed Safeer