3157 Stimmen

HTTP GET mit Anfragekörper

Ich entwickle gerade einen neuen RESTful Webservice für unsere Anwendung.

Bei einem GET auf bestimmte Entitäten können Clients den Inhalt der Entität anfordern. Wenn sie einige Parameter hinzufügen möchten (z. B. Sortieren einer Liste), können sie diese Parameter in den Abfrage-String einfügen.

Alternativ möchte ich, dass die Benutzer diese Parameter im Anfragetext angeben können. HTTP/1.1 scheint dies nicht ausdrücklich zu verbieten. Dadurch können sie mehr Informationen angeben, was die Angabe komplexer XML-Anfragen erleichtern könnte.

Meine Fragen:

  • Ist das überhaupt eine gute Idee?
  • Werden HTTP-Clients Probleme mit der Verwendung von Request Bodies innerhalb einer GET-Anfrage haben?

https://www.rfc-editor.org/rfc/rfc2616

620 Stimmen

Der Vorteil besteht darin, dass XML- oder JSON-Anfragekörper problemlos gesendet werden können, es gibt keine Längenbeschränkung und sie sind einfacher zu kodieren (UTF-8).

39 Stimmen

Wenn Sie eine sichere und idempotente Methode suchen, die Anfragekörper erlaubt, sollten Sie sich SEARCH, PROPFIND und REPORT ansehen. Wenn Sie GET nicht verwenden und einen Anfragebody haben, wird das Caching natürlich mehr oder weniger zunichte gemacht.

3 Stimmen

Unabhängig davon, ob die Spezifikation dies zulässt, verstößt es gegen den Geist von REST.

2517voto

Paul Morgan Punkte 28704

Roy Fieldings Bemerkung über das Einfügen eines Körpers in eine GET-Anfrage .

Mit anderen Worten, jede HTTP-Anforderungsnachricht darf einen Nachrichtentext enthalten und muss daher unter Berücksichtigung dieses Textes geparst werden. Die Serversemantik für GET ist jedoch so eingeschränkt, dass ein Body, falls vorhanden, keine semantische Bedeutung für die Anfrage hat. Die Anforderungen an das Parsing sind von den Anforderungen an die Methodensemantik getrennt.

Ja, Sie können einen Body mit GET senden, und nein, es ist nie sinnvoll, dies zu tun.

Dies ist Teil des mehrschichtigen Aufbaus von HTTP/1.1, der wieder deutlich werden wird, sobald die Spezifikation aufgeteilt ist (in Arbeit).

....Roy

Ja, Sie können einen Request Body mit GET senden, aber er sollte keine Bedeutung haben. Wenn Sie ihm eine Bedeutung geben, indem Sie ihn auf dem Server parsen und Ihre Antwort aufgrund des Inhalts zu ändern dann ignorieren Sie diese Empfehlung in die HTTP/1.1-Spezifikation, Abschnitt 4.3 :

...wenn die Anfragemethode keine definierte Semantik für einen Entity-Body enthält, dann wird der Message-Body SHOULD werden bei der Bearbeitung der Anfrage ignoriert.

Und die Beschreibung der GET-Methode in die HTTP/1.1-Spezifikation, Abschnitt 9.3 :

Die GET-Methode bedeutet, dass alle Informationen ([...]) abgerufen werden, die durch die Request-URI identifiziert werden.

der besagt, dass der Request-Body nicht Teil der Identifizierung der Ressource in einer GET-Anfrage ist, sondern nur der Request-URI.

Update

Der RFC2616, der als "HTTP/1.1 spec" bezeichnet wird, ist inzwischen veraltet. Im Jahr 2014 wurde er durch die RFCs 7230-7237 ersetzt. Das Zitat "the message-body SHOULD be ignored when handling the request" wurde gelöscht. Das zweite Zitat "Die GET-Methode bedeutet, dass alle Informationen, die durch die Request-URI identifiziert werden, abgerufen werden" wurde gelöscht. - Aus einem Kommentar

De la HTTP 1.1 2014 Spezifikation :

Eine Nutzlast innerhalb einer GET-Anforderungsnachricht hat keine definierte Semantik; das Senden eines Nutzlastkörpers bei einer GET-Anforderung könnte dazu führen, dass einige bestehende Implementierungen die Anforderung zurückweisen.

382voto

caskey Punkte 11625

Während Sie kann Ich würde vorschlagen, dies zu vermeiden, sofern es nicht ausdrücklich von der HTTP-Spezifikation ausgeschlossen wird, einfach weil die Leute nicht erwarten, dass die Dinge auf diese Weise funktionieren. Es gibt viele Phasen in einer HTTP-Anforderungskette, und obwohl sie "größtenteils" mit der HTTP-Spezifikation übereinstimmen, ist das Einzige, was man sicher sein kann, dass sie sich so verhalten, wie sie traditionell von Webbrowsern verwendet werden. (Ich denke dabei an Dinge wie transparente Proxys, Beschleuniger, A/V-Toolkits usw.)

Dies ist der Geist, der hinter dem Grundsatz der Robustheit Etwa nach dem Motto "Sei liberal in dem, was du akzeptierst, und konservativ in dem, was du sendest", sollte man die Grenzen einer Spezifikation nicht ohne guten Grund überschreiten.

Wenn Sie jedoch einen guten Grund haben, sollten Sie es tun.

254voto

Darrel Miller Punkte 133891

Sie werden wahrscheinlich auf Probleme stoßen, wenn Sie versuchen, das Caching zu nutzen. Proxies werden nicht in der GET Körper, um zu sehen, ob die Parameter Auswirkungen auf die Antwort haben.

110voto

Martin Andersson Punkte 15861

GET mit einer Leiche!?

Von der Spezifikation her könnten Sie das, aber es ist keine gute Idee, dies unüberlegt zu tun, wie wir sehen werden.

RFC 7231 §4.3.1 besagt, dass ein Körper "keine definierte Semantik hat", aber das bedeutet nicht, dass er verboten ist. Ob Sie einen Body an die Anfrage anhängen und was Ihr Server/Ihre Anwendung daraus macht, bleibt Ihnen überlassen. Im RFC heißt es weiter, dass GET "eine programmatische Sicht auf verschiedene Datenbankeinträge" sein kann. Offensichtlich wird eine solche Ansicht oft durch eine große Anzahl von Eingabeparametern zugeschnitten, die nicht immer bequem oder sogar sicher in der Abfragekomponente des Anfrageziels untergebracht werden können.

Das Gute: Mir gefällt der Wortlaut. Es ist klar, dass man eine Ressource ohne beobachtbare Nebeneffekte auf dem Server lesen/bekommen kann (die Methode ist "sicher"), und dass die Anfrage mit demselben beabsichtigten Effekt wiederholt werden kann, unabhängig vom Ergebnis der ersten Anfrage (die Methode ist "idempotent").

Das Schlechte: Ein früher Entwurf von HTTP/1.1 verbot GET, einen Body zu haben, und - angeblich - lassen einige Implementierungen sogar bis heute den Body weg, ignorieren ihn oder weisen die Nachricht zurück. Ein dummer HTTP-Cache kann zum Beispiel einen Cache-Schlüssel nur aus dem Request-Target konstruieren, ohne sich um das Vorhandensein oder den Inhalt eines Bodys zu kümmern. Ein noch dümmerer Server könnte so unwissend sein, dass er den Nachrichtentext als neue Anfrage behandelt, was als "Request Smuggling" bezeichnet wird (d.h. das Senden einer Anfrage an ein Gerät, ohne dass das andere Gerät davon weiß). source ).

Meiner Meinung nach ist dies in erster Linie auf die Inoperabilität der verschiedenen Implementierungen zurückzuführen, in Arbeit befindliche Maßnahmen schlägt vor, einen GET-Body als "SHOULD NOT", "" oder "" zu kategorisieren. es sei denn, [die Anfrage] direkt an einen Ursprungsserver gerichtet wird, der zuvor innerhalb oder außerhalb des Frequenzbands angegeben hat, dass eine solche Anfrage einen Zweck hat und angemessen unterstützt wird" (Hervorhebung von mir).

Die Lösung: Für einige der Probleme mit diesem Ansatz gibt es einige Hacks. Zum Beispiel können Caches, die keine Body-Aware sind, indirekt Body-Aware werden, indem sie einfach einen vom Body abgeleiteten Hash an die Abfragekomponente anhängen, oder das Caching insgesamt deaktivieren, indem sie eine Antwort auf cache-control: no-cache Kopfzeile des Servers.

Wenn es um die Anforderungskette geht, hat man leider oft nicht die Kontrolle über alle gegenwärtigen und zukünftigen HTTP-Vermittler und weiß nicht einmal, wie sie mit einem GET-Body umgehen werden. Deshalb muss dieser Ansatz als generell unzuverlässig angesehen werden.

Aber POST ist nicht idempotent!

POST ist eine Alternative. Die POST-Anfrage enthält in der Regel einen Nachrichtentext (nur zur Information, der Nachrichtentext ist keine Voraussetzung, siehe RFC 7230 §3.3.2 ). Das allererste Beispiel für einen Anwendungsfall aus RFC 7231 ( §4.3.3 ) ist die "Bereitstellung eines Datenblocks [...] an einen Datenverarbeitungsprozess". Genau wie bei GET mit einem Body liegt es also an Ihnen, was mit dem Body auf der Backend-Seite geschieht.

Das Gute: Vielleicht ist es eine gängigere Methode, die man anwenden kann, wenn man einen Anfragebody senden möchte, egal zu welchem Zweck, und die daher wahrscheinlich den geringsten Lärm von Ihren Teammitgliedern hervorrufen wird (einige mögen immer noch fälschlicherweise glauben, dass POST eine Ressource erstellen muss).

Außerdem übergeben wir oft Parameter an eine Suchfunktion, die mit sich ständig verändernden Daten arbeitet, und eine POST-Antwort ist nur dann cachefähig, wenn in der Antwort explizite Aktualitätsinformationen enthalten sind.

Das Schlechte: POST-Anfragen sind nicht als idempotent definiert, was zu einer zögerlichen Wiederholung von Anfragen führt. Beispielsweise sind Browser beim Neuladen einer Seite nicht bereit, ein HTML-Formular erneut zu übermitteln, ohne den Benutzer mit einer nicht lesbaren kryptischen Meldung zu konfrontieren.

Die Lösung: Nun, nur weil POST nicht als idempotent definiert ist, heißt das nicht, dass es das nicht sein darf. In der Tat, RFC 7230 §6.3.1 schreibt: "Ein User-Agent, der (durch Design oder Konfiguration) weiß, dass eine POST-Anfrage an eine bestimmte Ressource sicher ist, kann diese Anfrage automatisch wiederholen". Sofern es sich bei Ihrem Client nicht um ein HTML-Formular handelt, ist dies also wahrscheinlich kein echtes Problem.

QUERY ist der Heilige Gral

Es gibt einen Vorschlag für eine neue Methode QUERY die eine Semantik für einen Nachrichtenkörper definiert et definiert die Methode als idempotent. Siehe diese .

bearbeiten : Als Randnotiz stolperte ich in diese StackOverflow-Frage, nachdem ich eine Codebasis entdeckt hatte, in der ausschließlich verwendet wurde PUT Anfragen für serverseitige Suchfunktionen. Dies war ihre Idee, einen Body mit Parametern einzuschließen und auch idempotent zu sein. Das Problem mit PUT ist leider, dass der Anforderungskörper eine sehr präzise Semantik hat. Konkret fordert PUT, "dass der Zustand der Zielressource erstellt oder durch den Zustand [im Body] ersetzt wird" ( RFC 7231 §4.3.4 ). Dies schließt PUT als praktikable Option eindeutig aus.

104voto

jlecour Punkte 2755

Elasticsearch akzeptiert GET-Anfragen mit einem Body. Es scheint sogar, dass dies der bevorzugte Weg ist: Elasticsearch-Leitfaden

Einige Client-Bibliotheken (wie der Ruby-Treiber) können den Befehl cry im Entwicklungsmodus in stdout protokollieren und verwenden diese Syntax ausgiebig.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X