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.
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.
3 Stimmen
Viel Glück mit Kunden, die Abfragemethoden wie SEARCH implementieren. Es ist viel wahrscheinlicher, dass Sie GET + Body verwenden können. Aber Fiddler für eine nicht zulassen, obwohl die meisten Browser wird (oder haben in der Vergangenheit)
310 Stimmen
@fijiaaron: Es ist 3 Jahre später, und seitdem habe ich umfangreiche Erfahrungen mit dem Schreiben von Webservices gesammelt. Das ist im Grunde alles, was ich in den letzten paar Jahren gemacht habe. Ich kann mit Sicherheit sagen, dass es in der Tat eine sehr schlechte Idee ist, einen Body zu einer GET-Anfrage hinzuzufügen. Die ersten beiden Antworten stehen wie ein Fels in der Brandung.
1 Stimmen
Ich bin einverstanden. Es ist machbar, wenn man alles vom Client bis zum Server kontrolliert (aber wozu braucht man dann einen Webservice). Aber wenn jemand das möchte, kann er es tun, und anstatt zu sagen, dass etwas nicht möglich ist, können wir die Fallstricke erklären. Ich bin auf ähnliche Probleme gestoßen, und die beste Lösung, die mir eingefallen ist, ist die Verwendung von POST, und sagen Sie es nur nicht Roy Fielding, denn das würde ihn zum Weinen bringen.
0 Stimmen
@fijiaaron: Ich kann nicht für ihn sprechen, aber ich würde bezweifeln, dass er glaubt, dass reines REST das A und O ist. Wählen Sie das richtige Werkzeug für die Aufgabe. Er scheint sich jedoch sehr darum zu kümmern, dass der Begriff REST falsch verwendet wird.
3 Stimmen
@Evert: Besteht die Möglichkeit, dass Sie einige Details zu den Herausforderungen mitteilen, die Sie mit GETs und dem Senden von Inhalten im Body hatten? Ich schreibe meine erste API und ich denke, ich werde dazu gebracht, einen GET + Body-Ansatz zu verwenden. Es wäre nützlich, einige Beispiele aus der Praxis zu haben, in denen Schwierigkeiten aufgetreten sind, und mögliche Lösungen.
40 Stimmen
@Ellesedil: Einfach ausgedrückt: Die Vorteile, die die Verwendung von GET gegenüber POST bietet, ergeben sich aus der Art und Weise, wie HTTP konzipiert ist. Diese Vorteile gibt es nicht mehr, wenn man den Standard auf diese Weise verletzt. Daher gibt es nur noch einen Grund, GET + einen Request Body anstelle von POST zu verwenden: Ästhetik. Opfern Sie ein robustes Design nicht der Ästhetik.
2 Stimmen
Diese Antwort fasst es gut zusammen, indem sie sich auf die HTTP/1.1-Spezifikation bezieht - stackoverflow.com/a/15656853/244128
23 Stimmen
Um zu unterstreichen, was Evert sagte: "Es gibt keine Längenbeschränkung". Wenn Ihr GET mit Abfrageparametern gegen die Längenbeschränkung (von 2048) verstößt, gibt es keine andere Möglichkeit, als die Abfrage-String-Informationen in ein json-Objekt zu packen, z. B. in den Body der Anfrage.
1 Stimmen
Chiming in, nachdem vor kurzem ein Native Http-Modul in C++ für IIS8 gebaut, kann ich sagen, dass OnReadEntity nicht auf Get-Anforderungen, nur auf Beiträge Feuer, oder ich hatte extreme Schwierigkeiten, um den Körper einer Get-Anforderung...
1 Stimmen
@Evert Was machen Sie also am Ende? JSON-Parameter als Base64 kodieren?
0 Stimmen
@JulianReschke Können Sie Verweise auf SEARCH usw. bereitstellen? Sie scheinen nicht Teil der HTTP-Anforderungsmethoden zu sein (zumindest auf Wikipedia).
1 Stimmen
@beldaz Wikipedia ist irrelevant; siehe iana.org/assignments/http-methods/http-methods.xhtml
4 Stimmen
Der OP hat später seine Gedanken in einem interessanten Artikel die auf genau diese Frage hinweist.
1 Stimmen
@beldaz SEARCH ist eine WebDAV-Methode. Siehe RFC5323: Web Distributed Authoring and Versioning (WebDAV) SEARCH
9 Stimmen
Mit dem Aufkommen von GDPR und der Frage, was in der URL-Abfrage offengelegt (und somit protokolliert) werden darf, mussten wir unsere APIs umschreiben, um sensible Informationen im Anforderungskörper zu übergeben und GETs in POSTs zu ändern. Also, zum Beispiel
GET http://host/customer?socialsecuritynumber={ssn}
wurdePOST http://host/customer/lookup
mit den sensiblen Informationen im Textkörper, die von der externen und internen Protokollierung ausgeschlossen sind0 Stimmen
Was wird empfohlen, wenn die Anfrage komplexe Daten enthält? Sollten Sie POST verwenden, um Daten anzufordern?
0 Stimmen
Kein Wort über die Sicherheitsaspekte der Url-Kodierung von GET-Anfragen... Ich kenne einige Beispiele, bei denen das Spielen mit dem Parameterstring in einer solchen GET-"Url" Hintertüren zu Daten öffnete, die nicht für die Öffentlichkeit bestimmt waren (der Computerclub CHAOS hat das vorgemacht). Abgesehen davon, dass es begrenzt, unhandlich und hässlich ist, ist es auch anfälliger für gelegentliche Hackerangriffe. Aus diesem Grund habe ich nie verstanden, warum die Welt die URL-Kodierung der Eingabe von Abfragedaten in den GET-Body vorzieht.
0 Stimmen
@BitTickler, denn es ist nicht üblich, sie in den Text zu setzen. Verwenden Sie POST, wenn Sie diese Anforderung haben.
0 Stimmen
@Evert Es sieht aus wie ein Hack und war wahrscheinlich ein Hack, der dann als Standard verkündet wurde.
0 Stimmen
@BitTickler Ganz im Gegenteil.
GET
hat eine starke semantische Bedeutung und ist keine "Leseoperation". Es war ein Standard, lange bevor Sie versucht haben, ihn zu missbrauchen =). Warum wollen Sie verwendenGET
?2 Stimmen
@Evert Tut mir leid, dass ich Ihre Ruhe störe. Ich glaube einfach nicht, dass Briefe, die Sie erhalten, die Nachricht auf den Umschlag hätten schreiben sollen. Und genau das macht die URL-Kodierung. Es ist ein Hack. Jemand wollte die URL-Zeichenfolge zwischenspeichern und als Schlüssel verwenden. Jemand wollte das Adressfeld auf dem Briefumschlag für die eigentliche Nachricht missbrauchen. Ein hässlicher Hack.
0 Stimmen
@BitTickler das ist ein guter Punkt, zeigt aber auch ein Missverständnis, wofür GET gedacht ist. Man schickt keinen Brief; es ist eher so, dass man dem Server sagt: 'Gib mir das Objekt mit diesem Namen'. Wenn Sie dies überladen, um einen generischen RPC-Aufruf zum Lesen zu meinen, dann dass ist wirklich der Hack. Sie verwenden ihn nicht wie vorgesehen.
0 Stimmen
@BitTickler, dass es echte Anwendungsfälle für eine sichere, idempotente HTTP-Anfrage gibt, die eine Vielzahl von Parametern enthält, und es wird daran gearbeitet, Methoden dafür zu definieren (
SEARCH
yQUERY
).0 Stimmen
Es ist so traurig, dass etwas, das vom ETag-Caching extrem profitieren würde, weil es wahrscheinlich dieselbe Antwort wie beim letzten Mal ist und weil es ein großer Antwortkörper ist, wie ein Bericht, etwas sein muss, das nicht gecached werden kann.
3 Stimmen
@doug65536 Eine Sache, die Sie heute tun könnten, ist, die (kommende)
QUERY
http-Methode, verlangen einen Request-Header, der der (sha256?) Hash der Anfrage sein muss, und antworten dann mitVary: Your-Hash-Header
. Dadurch wird sichergestellt, dass Clients, die Caching unterstützenQUERY
speichert verschiedene Cache-Einträge für verschiedene Stellen. Ich glaube, es ist ein Standard für Body-Hashes in Arbeit, aber ich kann ihn gerade nicht finden.2 Stimmen
OP hat eine nette Folgefrage zu dieser Frage geschrieben: evertpot.com/get-request-bodies
0 Stimmen
In Anbetracht all dieser Informationen wird mein Ansatz auch Informationen über die Annahme einer Stelle mit einer
GET
Anfrage in meinemOPTIONS
Antworten von der Serverseite und passe meine Anfrage entsprechend an. Der Server könnte diese Informationen aus einer Konfigurationsdatei lesen, zusammen mit allen anderen Informationen über seine Umgebung, oder er kann in regelmäßigen Abständen eine "get"-Anfrage an sich selbst senden, die einen Body enthält. Caching sollte durch einen Hash in der Anfrage-URI oder in einem Header gelöst werden. Proxy Awareness sollte in der Verantwortung des Frontends liegen.0 Stimmen
@toraman das ist eine Menge von Workarounds, nur um eine nicht standardisierte, falsche und wahrscheinlich immer noch brüchige Lösung zu erreichen. Warum machen Sie es nicht richtig?
0 Stimmen
@Evert ist das nicht korrekt? Ich sehe keinen Sinn darin, zusätzlich zu dem, was in den Spezifikationen steht, noch mehr Strenge hinzuzufügen. Die Worte
SHOULD
,SHOULDN'T
usw. sind definierte, technische Begriffe in diesen Spezifikationen, sie sind nicht passiv-aggressiv, wenn sie sagen, dass SieMAY
etwas tun. Die Vorgaben sind klar, man kann einen Körper haben, aber niemand muss ihn berücksichtigen. Das ist genau das, was ich hier zu erfüllen versuche. Meine Gründe sind unter anderem, dass ich in der Lage bin, zu unterscheiden zwischentrue
y"true"
oufalse
,null
,"false"
,undefined
,""
,{}
y[]
.0 Stimmen
@toraman haben Sie den Artikel gelesen, den ich darüber geschrieben habe? Ich habe es dort angesprochen. Es ist definitiv verwirrend: evertpot.com/get-request-bodies . Aber warum sollten Sie sich diese Mühe machen, wenn Sie einfach die
QUERY
Methode an. Es ist perfekt für diesen Zweck, und keine seltsamen Workarounds mitOPTIONS
oder das Risiko, dass Zwischenprodukte aus dem Körper fallen.0 Stimmen
Mir gefällt Ihre Auffassung darüber, was die Spezifikationen für uns bedeuten sollten, obwohl ich denke, dass sie gute Arbeit leisten.
QUERY
wird nicht annähernd so stark unterstützt wieGET
mit einer Leiche.fetch()
scheint eine Ausnahme zu sein, aber soweit es sich umfetch()
betrifft eine Methode namensGETBUTWITHABODY
ist genauso gültig wieQUERY
. Ich kann nicht herausfinden, welche Browser einen CacheQUERY
Antwort auf den Antrag, aber ich glaube nicht, dass viele das tun werden. Außerdem sehe ich nicht, dass viele Backend-Frameworks dies auch unterstützen. Ich würde gerne wechseln zuQUERY
aber noch nicht. Mein Workaround scheint derzeit zuverlässiger zu sein.