Wie werden Parameter in einer HTTP-POST-Anfrage gesendet?

1476

In einer HTTP- GET- Anforderung werden Parameter als Abfragezeichenfolge gesendet :

http://example.com/page ? parameter = value & also = ein anderer

In einer HTTP- POST- Anforderung werden die Parameter nicht zusammen mit dem URI gesendet.

Wo sind die Werte? Im Anforderungsheader? Im Anfragetext? Wie sieht es aus?

Camilo Martin
quelle

Antworten:

1253

Die Werte werden im Anforderungshauptteil in dem vom Inhaltstyp angegebenen Format gesendet.

Normalerweise ist der Inhaltstyp application/x-www-form-urlencodedso, dass der Anforderungshauptteil dasselbe Format wie die Abfragezeichenfolge verwendet:

parameter=value&also=another

Wenn Sie einen Datei-Upload im Formular verwenden, verwenden Sie multipart/form-datastattdessen die Codierung, die ein anderes Format hat. Es ist komplizierter, aber Sie müssen sich normalerweise nicht darum kümmern, wie es aussieht, daher werde ich kein Beispiel zeigen, aber es kann gut sein zu wissen, dass es existiert.

Guffa
quelle
25
Ich hatte vergessen, dass das Hochladen von Dateien anders ist (+ 1 / akzeptiert). Ihre Antwort ist ausreichend, während es besonders schön wäre, wenn es mehr Informationen über hätte multipart/form-data. Für Interessierte ist hier eine Frage dazu .
Camilo Martin
73
HINWEIS : Der Text ist nur durch eine Leerzeile von der Kopfzeile getrennt .
Gab
2
Sie haben erklärt, was wir im HTTPBody platzieren, aber was platzieren / schreiben wir im HTTPHeader? Welchen Zweck erfüllt es?
Honey
4
@Honey: Der HTTP-Header für einen Beitrag sieht aus wie einer für einen get, jedoch mit dem Verb POST anstelle von GET und einem Inhaltstypwert (und einem optionalen Inhaltslängenwert), da die Anforderung Inhalt (body) enthält. Jeder Anforderungstyp hat einen Header, einige Typen haben auch einen Textkörper.
Guffa
4
@KennethWorden Nein, keine der Methoden sendet JSON ordnungsgemäß. Sie können jedoch eine JSON-Datei in einer Form hochladen, die mit codiert ist, multipart/form-dataoder wenn Sie für die Erstellung von Anforderungen verantwortlich sind, den Inhaltstyp ändern application/jsonund JSON-Text direkt in den http-Text
einfügen
428

Der Inhalt wird nach den HTTP-Headern eingefügt. Das Format eines HTTP-POST besteht darin, dass die HTTP-Header gefolgt von einer Leerzeile und dem Anforderungshauptteil angezeigt werden. Die POST-Variablen werden als Schlüssel-Wert-Paare im Body gespeichert.

Sie können dies im folgenden Rohinhalt eines HTTP-Posts sehen:

POST /path/script.cgi HTTP/1.0
From: [email protected]
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Sie können dies mit einem Tool wie Fiddler anzeigen , mit dem Sie die rohen HTTP-Anforderungs- und Antwortnutzdaten überwachen können, die über die Leitung gesendet werden.

Joe Alfano
quelle
39
Nur wenn der Inhaltstyp ist application/x-www-form-urlencoded, was nicht immer der Fall ist.
Guffa
@ Camilo Martin .... [+1] für eine großartige Frage & @ Joe Alfano .... [+1] für eine großartige Antwort ....... Ich habe jetzt eine klare Vorstellung von der POST-Anfrage .... aber wenn ein Bild mit Schlüssel, Wert, Dateninformationspaar geliefert wird ..... Wie sieht die Struktur von POST aus?
Devrath
9
@ Joe, warum solltest du dort einen FromHeader haben?
Pacerier
@ Joe, ich liebe die zufällige Aufnahme des FromHeaders. IMO ist es dort oben mit dem 418 HTTP-Statuscode.
Tom Howard
Wie füge ich eine Benutzer- und Kennwortauthentifizierung hinzu?
m4l490n
376

Kurze Antwort: Bei POST-Anfragen werden Werte im "Body" der Anfrage gesendet. Bei Webformularen werden sie höchstwahrscheinlich mit einem Medientyp von application/x-www-form-urlencodedoder gesendet multipart/form-data. Programmiersprachen oder Frameworks , die zu handhaben Web-Anfragen entwickelt wurden , in der Regel tun „The Right Thing ™“ mit solchen Anforderungen und bieten Ihnen einen einfachen Zugang zu den leicht dekodiert Werte (wie $_REQUESToder $_POSTin PHP, oder cgi.FieldStorage(), flask.request.formin Python).


Lassen Sie uns jetzt ein wenig abschweifen, was helfen kann, den Unterschied zu verstehen;)

Der Unterschied zwischen GETund POSTAnforderungen ist weitgehend semantisch. Sie werden auch unterschiedlich "verwendet", was den Unterschied in der Übergabe von Werten erklärt.

GET ( relevanter RFC-Abschnitt )

Wenn Sie eine GETAnforderung ausführen , fragen Sie den Server nach einer oder mehreren Entitäten. Damit der Client das Ergebnis filtern kann, kann er die sogenannte "Abfragezeichenfolge" der URL verwenden. Die Abfragezeichenfolge ist der Teil nach dem ?. Dies ist Teil der URI-Syntax .

Aus Sicht Ihres Anwendungscodes (des Teils, der die Anforderung empfängt ) müssen Sie den URI-Abfrageteil untersuchen, um Zugriff auf diese Werte zu erhalten.

Beachten Sie, dass die Schlüssel und Werte Teil des URI sind. Browser können die URI-Länge begrenzen. Der HTTP-Standard besagt, dass es keine Begrenzung gibt. Aber zum Zeitpunkt des Schreibens dieses Artikels, den meisten Browsern nicht begrenzen die URIs (Ich habe keine bestimmten Werte haben). GETAnforderungen sollten niemals verwendet werden, um neue Informationen an den Server zu senden. Besonders nicht größere Dokumente. Dort sollten Sie POSToder verwenden PUT.

POST ( relevanter RFC-Abschnitt )

Bei der Ausführung einer POSTAnforderung sendet der Client tatsächlich ein neues Dokument an den Remote-Host. Eine Abfragezeichenfolge ist also (semantisch) nicht sinnvoll. Aus diesem Grund haben Sie in Ihrem Anwendungscode keinen Zugriff darauf.

POSTist ein wenig komplizierter (und Weise flexibler):

Wenn Sie eine POST-Anfrage erhalten, sollten Sie immer eine "Nutzlast" oder, in HTTP-Begriffen, einen Nachrichtentext erwarten . Der Nachrichtentext an sich ist ziemlich nutzlos, da es kein Standardformat gibt (soweit ich das beurteilen kann. Vielleicht Anwendungs- / Oktett-Stream?). Das Body-Format wird durch den Content-TypeHeader definiert . Bei Verwendung eines HTML- FORMElements mit method="POST"ist dies normalerweise der Fall application/x-www-form-urlencoded. Ein weiterer sehr häufiger Typ sind mehrteilige / Formulardaten, wenn Sie Datei-Uploads verwenden. Aber es könnte alles sein , von text/plain, über application/jsonoder sogar ein Brauch application/octet-stream.

In jedem Fall sollte eine POSTAnforderung mit einem, Content-Typeder von der Anwendung nicht verarbeitet werden kann, einen 415Statuscode zurückgeben .

Die meisten Programmiersprachen (und / oder Web-Frameworks) bieten eine Möglichkeit , de / kodieren der Nachrichtentext von / zu den häufigsten Arten (wie application/x-www-form-urlencoded, multipart/form-dataoder application/json). Das ist also einfach. Benutzerdefinierte Typen erfordern möglicherweise etwas mehr Arbeit.

Am Beispiel eines Standarddokuments mit HTML-Formular sollte die Anwendung die folgenden Schritte ausführen:

  1. Lesen Sie das Content-TypeFeld
  2. Wenn der Wert nicht zu den unterstützten Medientypen gehört, geben Sie eine Antwort mit einem 415Statuscode zurück
  3. Andernfalls dekodieren Sie die Werte aus dem Nachrichtentext.

Auch hier werden Sprachen wie PHP oder Web-Frameworks für andere beliebte Sprachen dies wahrscheinlich für Sie erledigen. Die Ausnahme ist der 415Fehler. Kein Framework kann vorhersagen, welche Inhaltstypen Ihre Anwendung unterstützt und / oder nicht unterstützt. Es liegt an dir.

PUT ( relevanter RFC-Abschnitt )

Eine PUTAnfrage wird genauso behandelt wie eine POSTAnfrage. Der große Unterschied besteht darin, dass POSTder Server durch eine Anforderung entscheiden soll, wie (und wenn überhaupt) eine neue Ressource erstellt werden soll. In der Vergangenheit (ab dem inzwischen veralteten RFC2616 sollte eine neue Ressource als "Untergebener" (untergeordnetes Element) des URI erstellt werden, an den die Anforderung gesendet wurde).

Im PUTGegensatz dazu soll eine Anfrage eine Ressource genau an dieser URI und mit genau diesem Inhalt "hinterlegen" . Nicht mehr und nicht weniger. Die Idee ist, dass der Kunde dafür verantwortlich ist, die gesamte Ressource zu erstellen, bevor er sie "einfügt". Der Server sollte es so akzeptieren, wie es unter der angegebenen URL ist.

Infolgedessen wird eine POSTAnforderung normalerweise nicht zum Ersetzen einer vorhandenen Ressource verwendet. Eine PUTAnfrage kann sowohl erstellt als auch ersetzt werden.

Randnotiz

Es gibt auch " Pfadparameter ", mit denen zusätzliche Daten an die Fernbedienung gesendet werden können, aber sie sind so ungewöhnlich, dass ich hier nicht zu sehr ins Detail gehen werde. Als Referenz hier ein Auszug aus dem RFC:

Abgesehen von Punktsegmenten in hierarchischen Pfaden wird ein Pfadsegment von der generischen Syntax als undurchsichtig angesehen. URI-produzierende Anwendungen verwenden häufig die in einem Segment zulässigen reservierten Zeichen, um schemaspezifische oder Dereferenzierungshandler-spezifische Unterkomponenten abzugrenzen. Beispielsweise werden die reservierten Zeichen Semikolon (";") und Gleich ("=") häufig verwendet, um Parameter und Parameterwerte abzugrenzen, die für dieses Segment gelten. Das reservierte Komma (",") wird häufig für ähnliche Zwecke verwendet. Beispielsweise könnte ein URI-Produzent ein Segment wie "name; v = 1.1" verwenden, um einen Verweis auf Version 1.1 von "name" anzugeben, während ein anderer ein Segment wie "name, 1.1" verwenden könnte, um dasselbe anzugeben. Parametertypen können durch schemaspezifische Semantik definiert werden.

Exhuma
quelle
1
Ich könnte tatsächlich eine leichte Tangente genommen haben. Ich habe oben in der Antwort ein "tl; dr" hinzugefügt, um es klarer zu machen.
Exhuma
Ich habe es auch gerade bearbeitet, um auf RFC7231 anstelle von RFC2616 (das seit einiger Zeit veraltet ist) zu verweisen. Der Hauptunterschied für diese Antwort, abgesehen von den aktualisierten Links, liegt im Abschnitt "PUT".
Exhuma
Ich dachte, PUT würde anders gehandhabt als POST, da es idempotent sein soll? stackoverflow.com/questions/611906/…
Rogerdpack
1
@rogerdpack Du liegst nicht falsch. Wenn Sie den zweiten Absatz in dem gelesenen PUTAbschnitt werden Sie sehen , dass es ist idempotent. POSTim Gegensatz dazu kann - per Definition - nicht sein. POSTwird immer eine neue Ressource erstellen. PUTwird, wenn eine identische Ressource vorhanden ist, diese ersetzen. Wenn Sie also POST10 Mal anrufen , erstellen Sie 10 Ressourcen. Wenn Sie PUT10 Mal anrufen , wird (vielleicht) nur eines erstellt. Beantwortet das deine Frage?
Exhuma
59

Sie können es nicht direkt in die URL-Leiste des Browsers eingeben.

Sie können beispielsweise mit Live-HTTP-Headern sehen, wie POST-Daten im Internet gesendet werden . Ergebnis wird so etwas sein

http://127.0.0.1/pass.php
POST /pass.php HTTP/1.1

Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/pass.php
Cookie: passx=87e8af376bc9d9bfec2c7c0193e6af70; PHPSESSID=l9hk7mfh0ppqecg8gialak6gt5
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=zurfyx&pass=password

Wo steht

Content-Length: 30
    username=zurfyx&pass=password

werden die Post-Werte sein.

zurfyx
quelle
2
Klarstellung: Content-Lengthsoll 29hier sein? Das ist die tatsächliche Länge der Zeichenfolge username=zurfyx&pass=password.
Hippo
@ Hippo war ein Newline-Charakter, der da sein sollte?
Wikingersteve
@ Vikingsteve Ich verstehe, was du meinst. Ich denke, der Inhalt hat dann immer eine neue Zeile am Ende.
Hippo
2
Der Header wird durch zusätzliche Newline vom Körper getrennt
Mára Toner
24

Der Standardmedientyp in einer POST-Anforderung ist application/x-www-form-urlencoded. Dies ist ein Format zum Codieren von Schlüssel-Wert-Paaren. Die Schlüssel können doppelt vorhanden sein. Jedes Schlüssel-Wert-Paar ist durch ein &Zeichen getrennt, und jeder Schlüssel ist durch ein =Zeichen von seinem Wert getrennt .

Zum Beispiel:

Name: John Smith
Grade: 19

Ist codiert als:

Name=John+Smith&Grade=19

Dies wird im Anforderungshauptteil nach den HTTP-Headern platziert.

Nejat
quelle
1
Sie haben erklärt, was wir im HTTPBody platzieren, aber was platzieren / schreiben wir im HTTPHeader?
Honey
Sie haben erwähnt, dass der Schlüssel doppelt vorhanden sein kann. Was ist dann das Ergebnis eines solchen Duplikats? Überschreibt der letzte automatisch die vorherigen Werte? Vielen Dank.
Jinghui Niu
@JinghuiNiu Wenn der Schlüssel doppelt vorhanden ist, sollte er als Array analysiert werden. Dies ist sehr spät, könnte aber jemand anderem helfen.
Hanash Yaslem
18

Formularwerte in HTTP-POSTs werden im Anforderungshauptteil im selben Format wie der Querystring gesendet.

Weitere Informationen finden Sie in der Spezifikation .

SLaks
quelle
5
"Gleiches Format" ist etwas mehrdeutig. Beginnen sie ?zum Beispiel mit einem ?
Camilo Martin
7
@PeterWooster Ja, bietet aber kein Beispiel. In dieser Hinsicht ist es wie eine Antwort, die sagt "Schau, es gibt eine Antwort auf deine Frage im Blog der Anwendung (Link) ".
Camilo Martin
36
@PeterWooster Es wird nicht benötigt, aber es ist sehr gut, wenn Sie etwas vergessen, googeln, zum ersten Link gehen, der SO ist, und es gibt ein klares, präzises Beispiel, das Ihnen sagt, was Sie brauchen, anstatt Sie zum Kauen zu schicken übermäßig detaillierte Spezifikationen, die, selbst wenn sie umfassend sind, möglicherweise nicht für Auffrischungen geeignet sind. Denken Sie darüber nach: Die meisten QAs auf dieser Website könnten sich auf "Lesen Sie die Spezifikation / Handbuch / API / etc (Link) " beschränken. Wäre es nützlich? Nicht mehr als Google.
Camilo Martin
2
Nur wenn der Inhaltstyp ist application/x-www-form-urlencoded, was nicht immer der Fall ist.
Guffa
3
Das Format der GET-Abfragezeichenfolge unterscheidet sich von dem der Anwendung / x-www-form-urlencoded. Beispielsweise wird Leerzeichen anders codiert (% 20 vs +). Die Antwort ist in dieser Hinsicht irreführend.
UnclickableCharacter
18

Einige der Web Service benötigen Sie Platz Anfrage Daten und Metadaten getrennt. Beispielsweise kann eine Remote-Funktion erwarten, dass die signierte Metadatenzeichenfolge in einem URI enthalten ist, während die Daten in einem HTTP-Body veröffentlicht werden.

Die POST-Anforderung kann semantisch folgendermaßen aussehen:

POST /?AuthId=YOURKEY&Action=WebServiceAction&Signature=rcLXfkPldrYm04 HTTP/1.1
Content-Type: text/tab-separated-values; charset=iso-8859-1
Content-Length: []
Host: webservices.domain.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

name    id
John    G12N
Sarah   J87M
Bob     N33Y

Dieser Ansatz kombiniert QueryString und Body-Post logisch mit einer einzigen, Content-Typedie eine "Parsing-Anweisung" für einen Webserver darstellt.

Bitte beachten Sie: HTTP / 1.1 wird mit dem (Leerzeichen) links und mit (Zeilenvorschub) rechts umbrochen .#32#10

Schnittstelle unbekannt
quelle
Der Unterschied zwischen /user/johnund /?user=johnist lediglich ein semantischer Unterschied (HTTP behandelt Abfragezeichenfolgen nicht wirklich speziell), daher nehme ich dies als vernünftigerweise erwartet an. Aber was meinst du mit "links vom Leerzeichen umhüllt"? Vor der HTTP-Methode stehen keine Leerzeichen. Du meinst die leere Zeile für Postkörper?
Camilo Martin
Zwischen ...Ym04und HTTP/1.1im obigen Code befindet sich ein Leerzeichen (ASCII # 32) . Ein QueryString befindet sich also einfach zwischen dem Verb und der Protokollversion.
Schnittstelle unbekannt
1
Ihre Notiz klingt wie etwas Unerwartetes und Versionsspezifisches. Ehrlich gesagt scheint es offensichtlich, dass dort ein Platz ist. Und der Zeilenvorschub gilt auch für die anderen Zeilen, wie alles Unix.
Camilo Martin
1
Ich habe nur betont, was ich im Code nicht markieren konnte. Es mag offensichtlich erscheinen, ist es aber manchmal nicht.
Schnittstelle unbekannt
Es ist wahr, dass wir die Abfrageparameter als Teil der URL übergeben könnten, indem wir den URI und die Parameter so trennen, ?wie wir es bei GETAnfragen tun .
Asgs
8

Lassen Sie uns zunächst zwischen GETund unterscheidenPOST

Get: Dies ist die Standardanforderung HTTP, die an den Server gestellt wird und zum Abrufen der Daten vom Server verwendet wird. Die Abfragezeichenfolge, die ?in a URIfolgt, wird zum Abrufen einer eindeutigen Ressource verwendet.

Das ist das Format

GET /someweb.asp?data=value HTTP/1.0

Hier data=valuewird der Wert der Abfragezeichenfolge übergeben.

POST: Es wird verwendet, um Daten sicher an den Server zu senden. Alles, was benötigt wird, ist das Format einer POSTAnfrage

POST /somweb.aspHTTP/1.0
Host: localhost
Content-Type: application/x-www-form-urlencoded //you can put any format here
Content-Length: 11 //it depends
Name= somename

Warum POST über GET?

In GETdem Wert für die Server sind in der Regel auf die Basis - URL in dem Query - String angehängt gesendet werden, jetzt gibt es zwei Folgen davon

  • Die GETAnfragen werden mit den Parametern im Browserverlauf gespeichert. So bleiben Ihre Passwörter im Browserverlauf unverschlüsselt. Dies war damals ein echtes Problem für Facebook.
  • Normalerweise haben Server eine Begrenzung, wie lange a sein URIkann. Wenn zu viele Parameter gesendet werden, erhalten Sie möglicherweise414 Error - URI too long

Im Falle einer Nachanfrage werden stattdessen Ihre Daten aus den Feldern dem Text hinzugefügt. Die Länge der Anforderungsparameter wird berechnet und dem Header für die Inhaltslänge hinzugefügt, und es werden keine wichtigen Daten direkt an die URL angehängt.

Im Netzwerkbereich der Google Developer Tools können Sie grundlegende Informationen dazu anzeigen, wie Anforderungen an die Server gestellt werden.

und Sie können immer mehr Werte in Ihrer hinzufügen Request Headerswie Cache-Control, Origin, Accept.

Zeeshan Adil
quelle
4
Die Annahmen zur Sicherheit gelten nur im Zusammenhang mit einer HTTPSVerbindung, nicht HTTP. HTTPSverschlüsselt sowohl die URL(einschließlich der Abfrageparameter) als auch die Request Body, wenn HTTPkeine verschlüsselt / geschützt wird . Das beschriebene Problem beruht auf der Tatsache, dass viele Browser die URIs(einschließlich URLs) in ihren Verlaufsdatenbanken speichern (normalerweise nicht verschlüsselt). Verwenden Sie also nur das Request Body+ HTTPSfür alles, was empfindlich ist.
Petru Zaharia
@ PetruZaharia Ich stimme Ihrer Erklärung zu. Sie können dies auch als Bearbeitung vorschlagen und ich werde es gerne akzeptieren! :)
Zeeshan Adil