HTTP POST mit URL-Abfrageparametern - gute Idee oder nicht? [geschlossen]

451

Ich entwerfe eine API für HTTP und frage mich, ob die Verwendung des Befehls HTTP POST, jedoch nur mit URL-Abfrageparametern und ohne Anforderungshauptteil, ein guter Weg ist.

Überlegungen:

  • "Gutes Webdesign" erfordert, dass nicht idempotente Aktionen per POST gesendet werden. Dies ist eine nicht idempotente Aktion.
  • Es ist einfacher, diese App zu entwickeln und zu debuggen, wenn die Anforderungsparameter in der URL vorhanden sind.
  • Die API ist nicht für eine breite Verwendung vorgesehen.
  • Es scheint, als würde das Erstellen einer POST-Anfrage ohne Text etwas mehr Arbeit Content-Length: 0erfordern , z. B. muss ein Header explizit hinzugefügt werden.
  • Es scheint mir auch, dass ein POST ohne Body den Erwartungen der meisten Entwickler- und HTTP-Frameworks etwas widerspricht.

Gibt es weitere Fallstricke oder Vorteile beim Senden von Parametern für eine POST-Anforderung über die URL-Abfrage anstelle des Anforderungshauptteils?

Bearbeiten: Der Grund, warum dies in Betracht gezogen wird, ist, dass die Operationen nicht idempotent sind und andere Nebenwirkungen als das Abrufen haben. Siehe die HTTP-Spezifikation :

Insbesondere wurde die Konvention festgelegt, dass die Methoden GET und HEAD NICHT die Bedeutung haben sollten, eine andere Aktion als das Abrufen durchzuführen. Diese Methoden sollten als "sicher" angesehen werden. Auf diese Weise können Benutzeragenten andere Methoden wie POST, PUT und DELETE auf besondere Weise darstellen, sodass der Benutzer darauf aufmerksam gemacht wird, dass eine möglicherweise unsichere Aktion angefordert wird.

...

Methoden können auch die Eigenschaft "Idempotenz" haben, da (abgesehen von Fehler- oder Ablaufproblemen) die Nebenwirkungen von N> 0 identischen Anforderungen dieselben sind wie für eine einzelne Anforderung. Die Methoden GET, HEAD, PUT und DELETE teilen diese Eigenschaft. Außerdem sollten die Methoden OPTIONS und TRACE KEINE Nebenwirkungen haben und sind daher von Natur aus idempotent.

Steven Huwig
quelle
11
Warum POST überhaupt verwenden, wenn Sie keine Daten im Körper bereitstellen möchten?
Sunny Milenov
114
Weil die Operation nicht idempotent ist.
Steven Huwig
20
@Jared, beachte, dass das Wort "REST" in dieser Frage seit 2,5 Jahren nicht mehr vorkommt. :) Die HTTP-Spezifikation zur Idempotenz gilt unabhängig von der Architektur des Monats für Webdienste. Glücklicherweise ist das System, für das diese API als Proxy entwickelt wurde, ohnehin veraltet.
Steven Huwig
5
Weil Serverprotokolle keine POST-Parameter aufzeichnen, sondern Abfragezeichenfolgen aufzeichnen. Es ist viel einfacher, die Reihe von Anforderungen auszuführen, ohne sie im Browser zu instrumentieren, und dann den Traceback zu betrachten, als sie durchzuklicken. Auch die API war nicht Browser-zu-Server, sondern Server-zu-Server. Am wichtigsten war, dass die ganze Angelegenheit sowieso in Dosen war. :)
Steven Huwig
13
Für alle anderen, die nicht wissen, was idempotent bedeutet: | restapitutorial.com/lessons/idempotency.html
Christopher Grigg

Antworten:

259

Wenn die Aktion nicht idempotent, dann Sie muss verwenden POST. Wenn Sie dies nicht tun, bitten Sie nur um Ärger auf der ganzen Linie. GET, PUTUnd DELETEsind Verfahren erforderlich sein idempotent. Stellen Sie sich vor, was in Ihrer Anwendung passieren würde, wenn der Client jede mögliche GETAnforderung für Ihren Service vorab abrufen würde. Wenn dies für den Client sichtbare Nebenwirkungen verursachen würde, stimmt etwas nicht.

Ich bin damit einverstanden, dass das Senden eines POSTmit einer Abfragezeichenfolge, jedoch ohne Text, seltsam erscheint, aber ich denke, dass dies in einigen Situationen angemessen sein kann.

Stellen Sie sich den Abfrageteil einer URL als Befehl an die Ressource vor, um den Umfang der aktuellen Anforderung einzuschränken. Normalerweise werden Abfragezeichenfolgen verwendet, um eine GETAnfrage zu sortieren oder zu filtern (wie ?page=1&sort=title), aber ich nehme an, dass es sinnvoll ist POST, auch den Umfang zu begrenzen (vielleicht wie ?action=delete&id=5).

Don McCaughey
quelle
4
Ich habe diese Antwort für diesen speziellen Fall ausgewählt, aber ich denke, dass das Argument von R. Bemrose für öffentliche APIs überzeugend ist.
Steven Huwig
4
Ich denke nicht, dass seine Antwort genau richtig ist. Wenn Sie die URL-Parameter für Ihren Formularbeitrag kennen, wenn die HTML-Seite an den Client gesendet wird, können Sie diese URL-Parameter an das Aktionsattribut des Formulars anheften. Andernfalls kann JavaScript die URL-Parameter beim Senden des Formulars festlegen.
Don McCaughey
3
Wie wäre es mit einem Beitrag einer XML-Datei in eine URL mit Abfrageparametern? ist das möglich?
OpenCoderX
3
Ein weiteres Beispiel: Die Anforderungsdaten könnten sich in der http-Entität befinden, während das angeforderte Format der Antwort im Abfrageparameter ( /action?response_format=json)
rds
4
+1 hat heute etwas gelernt. Löschen hat die technische Bedeutung, idempotent zu sein. Wenn das Objekt tatsächlich gelöscht wird, erhalten Sie eine nicht gefundene 404, sodass der Server denselben Status hat, die Antwort jedoch unterschiedlich ist. Siehe Kuh Bild: restapitutorial.com/lessons/idempotency.html
JPK
131

Jeder hat Recht: Bleiben Sie bei POST für nicht idempotente Anfragen.

Was ist mit der Verwendung einer URI-Abfragezeichenfolge und des Anforderungsinhalts? Nun, es ist gültiges HTTP (siehe Anmerkung 1). Warum also nicht?!

Es ist auch vollkommen logisch: URLs, einschließlich ihres Abfragezeichenfolgenteils, dienen zum Auffinden von Ressourcen. Während HTTP-Methodenverben (POST - und sein optionaler Anforderungsinhalt) dazu dienen, Aktionen anzugeben oder was mit Ressourcen zu tun ist . Dies sollten orthogonale Bedenken sein. (Für den Sonderfall von ContentType = application / x-www-form-urlencoded sind sie jedoch keine besonders orthogonalen Bedenken, siehe Anmerkung 2 unten.)

Hinweis 1: In der HTTP-Spezifikation (1.1) wird nicht angegeben, dass sich Abfrageparameter und Inhalt für einen HTTP-Server, der POST- oder PUT-Anforderungen akzeptiert, gegenseitig ausschließen. Jeder Server kann also beide akzeptieren. Das heißt, wenn Sie den Server schreiben, hindert Sie nichts daran, beide zu akzeptieren (außer vielleicht einem unflexiblen Framework). Im Allgemeinen kann der Server Abfragezeichenfolgen nach beliebigen Regeln interpretieren. Es kann sie sogar mit bedingter Logik interpretieren, die sich auch auf andere Header wie Content-Type bezieht, was zu Anmerkung 2 führt:

Hinweis 2: Wenn ein Webbrowser die primäre Art ist, wie Benutzer auf Ihre Webanwendung zugreifen, und application / x-www-form-urlencoded der Inhaltstyp ist, den sie veröffentlichen, sollten Sie die Regeln für diesen Inhaltstyp befolgen. Und die Regeln für application / x-www-form-urlencoded sind viel spezifischer (und offen gesagt ungewöhnlich): In diesem Fall müssen Sie den URI als eine Reihe von Parametern und nicht als Ressourcenspeicherort interpretieren. [Dies ist derselbe Punkt der Nützlichkeit, den Powerlord angesprochen hat. Es kann schwierig sein, Webformulare zu verwenden, um Inhalte auf Ihrem Server zu veröffentlichen. Nur ein bisschen anders erklärt.]

Hinweis 3: Wofür sind Abfragezeichenfolgen ursprünglich gedacht? RFC 3986 definiert HTTP-Abfragezeichenfolgen als URI-Teil, der als nicht hierarchische Methode zum Auffinden einer Ressource dient.

Falls Leser, die diese Frage stellen, fragen möchten, was eine gute RESTful-Architektur ist: Für das RESTful-Architekturmuster sind keine URI-Schemata erforderlich, um auf eine bestimmte Weise zu funktionieren. Die RESTful-Architektur befasst sich mit anderen Eigenschaften des Systems, wie der Cachefähigkeit von Ressourcen, dem Design der Ressourcen selbst (deren Verhalten, Fähigkeiten und Darstellungen) und der Frage, ob die Idempotenz erfüllt ist. Mit anderen Worten: Erzielen eines Designs, das in hohem Maße mit dem HTTP-Protokoll und seinen HTTP-Methodenverben kompatibel ist. :-) (Mit anderen Worten, ist RESTful - Architektur nicht sehr presciptive mit , wie die Ressourcen befinden .)

Schlussbemerkung: Manchmal werden Abfrageparameter für andere Dinge verwendet, bei denen weder Ressourcen gefunden noch Inhalte codiert werden. Haben Sie jemals einen Abfrageparameter wie 'PUT = true' oder 'POST = true' gesehen? Dies sind Problemumgehungen für Browser, in denen Sie keine PUT- und POST-Methoden verwenden können. Während solche Parameter als Teil der URL-Abfragezeichenfolge (auf der Leitung) gesehen werden, argumentiere ich, dass sie nicht Teil der URL-Abfrage im Geiste sind .

Tim Lovell-Smith
quelle
66

Du willst Gründe? Hier ist eine:

Ein Webformular kann nicht zum Senden einer Anfrage an eine Seite verwendet werden, die eine Mischung aus GET und POST verwendet. Wenn Sie die Methode des Formulars auf GET setzen, befinden sich alle Parameter in der Abfragezeichenfolge. Wenn Sie die Methode des Formulars auf POST setzen, befinden sich alle Parameter im Anforderungshauptteil.

Quelle: HTML 4.01 Standard, Abschnitt 17.13 Formularübermittlung

Powerlord
quelle
10
Das ist ein anständiges Argument, aber ich denke, die Javascript-Implementierungen moderner Browser machen es zu einem strittigen Punkt. Ich werde jedoch darüber nachdenken - es ist in einer zukunftssicheren Art überzeugend. Nur weil ich jetzt kein Formular dafür verwende, heißt das nicht, dass ich es später nicht mehr möchte.
Steven Huwig
9
Das Mischen von GET mit POST ist nur eine wirklich schlechte Idee - HTTP schrecklich zu brechen und das ohne guten Grund.
Aehlke
6
Dieser Ausschnitt erscheint nicht auf der Seite, auf die Sie verlinkt haben
Gareth
40
Richtig, aber das Methodenattribut definiert nur, wie der "Formulardatensatz" in der Anforderung enthalten ist. Wenn dies methodPOST ist, wird nicht erwähnt, dass der URI in den Formularen geändert wird action. Und jeder URI kann natürlich bereits einen Abfragezeichenfolgen-Teil enthalten.
Gareth
16
@ Powerlord Das ist einfach falsch. Versuchen Sie, ein Formular für POST mit einer Aktion von z. /Books?bookCode=1234. Der Webserver erhält POST-Formularvariablen und eine Abfragezeichenfolge.
Jez
9

Aus programmatischer Sicht packt der Client Parameter zusammen, hängt sie an die URL an und führt einen POST gegen einen GET durch. Auf der Serverseite werden eingehende Parameter aus dem Querystring anstelle der gesendeten Bytes ausgewertet. Im Grunde ist es eine Wäsche.

Es kann Vor- / Nachteile geben, wie bestimmte Clientplattformen mit POST- und GET-Routinen in ihrem Netzwerkstapel arbeiten und wie der Webserver mit diesen Anforderungen umgeht. Abhängig von Ihrer Implementierung ist ein Ansatz möglicherweise effizienter als der andere. Zu wissen, dass dies Ihre Entscheidung hier leiten würde.

Aus Sicht eines Programmierers bevorzuge ich es jedoch, entweder einen POST mit allen Parametern im Textkörper oder einen GET mit allen Parametern in der URL zuzulassen und URL-Parameter bei jeder POST-Anforderung explizit zu ignorieren. Es vermeidet Verwirrung.

jro
quelle
8

Ich würde denken, dass es immer noch ziemlich RESTful sein könnte, Abfrageargumente zu haben, die die Ressource auf der URL identifizieren, während die Nutzdaten des Inhalts auf den POST-Body beschränkt bleiben. Dies scheint die Überlegungen zu "Was sende ich?" versus "An wen sende ich es?".

swizzcheez
quelle
5
Die Frage war nicht über REST.
Steven Huwig
3
@ user359996 Nicht alle HTTP-APIs sind REST-fähig. In der Tat sind die meisten APIs, die behaupten, dass dies tatsächlich nicht der Fall ist. Außerdem ist REST nicht nur HTTP-fähig.
Alec Mev
4

Das REST- Camp hat einige Leitprinzipien, mit denen wir die Art und Weise, wie wir HTTP-Verben verwenden, standardisieren können. Dies ist hilfreich, wenn Sie gerade RESTful-APIs erstellen.

Kurz gesagt: GET sollte schreibgeschützt sein, dh keine Auswirkungen auf den Serverstatus haben. POST wird verwendet, um eine Ressource auf dem Server zu erstellen. PUT wird zum Aktualisieren oder Erstellen einer Ressource verwendet. DELETE wird zum Löschen einer Ressource verwendet.

Mit anderen Worten, wenn Ihre API-Aktion den Serverstatus ändert, empfiehlt REST, POST / PUT / DELETE, jedoch nicht GET zu verwenden.

Benutzeragenten verstehen normalerweise, dass das Ausführen mehrerer POSTs schlecht ist und warnen davor, da die Absicht des POST darin besteht, den Serverstatus zu ändern (z. B. für Waren an der Kasse zu bezahlen), und Sie möchten dies wahrscheinlich nicht zweimal tun!

Vergleichen Sie mit einem GET, das Sie oft nach Belieben ausführen können (idempotent).

Saille
quelle
13
Das REST-Camp sagt, Sie sollten HTTP verwenden, wie in der HTTP-Spezifikation definiert. dh RFC2616 Nicht mehr und nicht weniger.
Darrel Miller
1
@Darrel Verweisen auf ibm.com/developerworks/webservices/library/ws-restful : REST fordert Entwickler auf, HTTP-Methoden explizit und in einer Weise zu verwenden, die mit der Protokolldefinition übereinstimmt. Dieses grundlegende REST-Entwurfsprinzip erstellt eine Eins-zu-Eins-Zuordnung zwischen CRUD-Operationen (Erstellen, Lesen, Aktualisieren und Löschen) und HTTP-Methoden. Entsprechend dieser Zuordnung: Verwenden Sie POST, um eine Ressource auf dem Server zu erstellen. Verwenden Sie GET, um eine Ressource abzurufen. Verwenden Sie PUT, um den Status einer Ressource zu ändern oder zu aktualisieren. Verwenden Sie DELETE, um eine Ressource zu entfernen oder zu löschen.
Saille
5
Entschuldigung, aber das ist einfach falsch. REST erfordert die Einhaltung einer einheitlichen Schnittstelle. Wenn Sie HTTP verwenden, wird diese einheitliche Schnittstelle teilweise durch RFC 2616 definiert. In dieser Spezifikation gibt es keine Eins-zu-Eins-Zuordnung zwischen Erstellen, Lesen, Aktualisieren und Löschen und den HTTP-Methoden.
Darrel Miller
3
GET und DELETE lassen sich gut in CRUD lesen und löschen, aber die Verwendung von PUT / POST zum Aktualisieren und Erstellen ist nicht so einfach. Siehe stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw
5
Wenn ich 6 Jahre später darauf zurückblicke und die Frage ~ 100.000 Mal angesehen wurde, halte ich es für sinnvoll, ein kleines Update einzufügen. Darrel ist gemäß Fieldings Definition von REST ( ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm ) korrekt - es wird nicht erwähnt, dass HTTP-Verben CRUD zugeordnet werden. Die Entwicklerempfehlungen von IBM (Link im Kommentar oben) spiegeln die gängige Praxis bei der Implementierung von RESTful-APIs wider, nicht die Definition von REST durch Fielding.
Saille
-13

Ich stimme zu - es ist wahrscheinlich sicherer, eine GET-Anfrage zu verwenden, wenn Sie nur Daten in der URL und nicht im Text übergeben. In dieser ähnlichen Frage finden Sie einige zusätzliche Ansichten zum gesamten POST + GET-Konzept.

Marc Novakowski
quelle
17
Wenn die Operation Nebenwirkungen hat, ist die Verwendung der GET-Methode sicherlich nicht "sicherer", da der Browser davon ausgeht, dass alle GETs idempotent sind.
DCstraw
Suchmaschinen konvertieren dies auch in einen Albtraum, da Google sicher auf alle Links mit GET-Anfrage "klickt", aber alles andere weglässt. Es ist nicht so sicher, einen Dienst zu verlassen, dass ein unschuldiger Crawler versehentlich die Datenbank löschen kann.
Alejandro