How are parameters sent in an HTTP POST request?

2,473,155

Solution 1

The values are sent in the request body, in the format that the content type specifies.

Usually the content type is application/x-www-form-urlencoded, so the request body uses the same format as the query string:

parameter=value&also=another

When you use a file upload in the form, you use the multipart/form-data encoding instead, which has a different format. It's more complicated, but you usually don't need to care what it looks like, so I won't show an example, but it can be good to know that it exists.

Solution 2

The content is put after the HTTP headers. The format of an HTTP POST is to have the HTTP headers, followed by a blank line, followed by the request body. The POST variables are stored as key-value pairs in the body.

You can see this in the raw content of an HTTP Post, shown below:

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

You can see this using a tool like Fiddler, which you can use to watch the raw HTTP request and response payloads being sent across the wire.

Solution 3

Short answer: in POST requests, values are sent in the "body" of the request. With web-forms they are most likely sent with a media type of application/x-www-form-urlencoded or multipart/form-data. Programming languages or frameworks which have been designed to handle web-requests usually do "The Right Thing™" with such requests and provide you with easy access to the readily decoded values (like $_REQUEST or $_POST in PHP, or cgi.FieldStorage(), flask.request.form in Python).


Now let's digress a bit, which may help understand the difference ;)

The difference between GET and POST requests are largely semantic. They are also "used" differently, which explains the difference in how values are passed.

GET (relevant RFC section)

When executing a GET request, you ask the server for one, or a set of entities. To allow the client to filter the result, it can use the so called "query string" of the URL. The query string is the part after the ?. This is part of the URI syntax.

So, from the point of view of your application code (the part which receives the request), you will need to inspect the URI query part to gain access to these values.

Note that the keys and values are part of the URI. Browsers may impose a limit on URI length. The HTTP standard states that there is no limit. But at the time of this writing, most browsers do limit the URIs (I don't have specific values). GET requests should never be used to submit new information to the server. Especially not larger documents. That's where you should use POST or PUT.

POST (relevant RFC section)

When executing a POST request, the client is actually submitting a new document to the remote host. So, a query string does not (semantically) make sense. Which is why you don't have access to them in your application code.

POST is a little bit more complex (and way more flexible):

When receiving a POST request, you should always expect a "payload", or, in HTTP terms: a message body. The message body in itself is pretty useless, as there is no standard (as far as I can tell. Maybe application/octet-stream?) format. The body format is defined by the Content-Type header. When using a HTML FORM element with method="POST", this is usually application/x-www-form-urlencoded. Another very common type is multipart/form-data if you use file uploads. But it could be anything, ranging from text/plain, over application/json or even a custom application/octet-stream.

In any case, if a POST request is made with a Content-Type which cannot be handled by the application, it should return a 415 status-code.

Most programming languages (and/or web-frameworks) offer a way to de/encode the message body from/to the most common types (like application/x-www-form-urlencoded, multipart/form-data or application/json). So that's easy. Custom types require potentially a bit more work.

Using a standard HTML form encoded document as example, the application should perform the following steps:

  1. Read the Content-Type field
  2. If the value is not one of the supported media-types, then return a response with a 415 status code
  3. otherwise, decode the values from the message body.

Again, languages like PHP, or web-frameworks for other popular languages will probably handle this for you. The exception to this is the 415 error. No framework can predict which content-types your application chooses to support and/or not support. This is up to you.

PUT (relevant RFC section)

A PUT request is pretty much handled in the exact same way as a POST request. The big difference is that a POST request is supposed to let the server decide how to (and if at all) create a new resource. Historically (from the now obsolete RFC2616 it was to create a new resource as a "subordinate" (child) of the URI where the request was sent to).

A PUT request in contrast is supposed to "deposit" a resource exactly at that URI, and with exactly that content. No more, no less. The idea is that the client is responsible to craft the complete resource before "PUTting" it. The server should accept it as-is on the given URL.

As a consequence, a POST request is usually not used to replace an existing resource. A PUT request can do both create and replace.

Side-Note

There are also "path parameters" which can be used to send additional data to the remote, but they are so uncommon, that I won't go into too much detail here. But, for reference, here is an excerpt from the RFC:

Aside from dot-segments in hierarchical paths, a path segment is considered opaque by the generic syntax. URI producing applications often use the reserved characters allowed in a segment to delimit scheme-specific or dereference-handler-specific subcomponents. For example, the semicolon (";") and equals ("=") reserved characters are often used to delimit parameters and parameter values applicable to that segment. The comma (",") reserved character is often used for similar purposes. For example, one URI producer might use a segment such as "name;v=1.1" to indicate a reference to version 1.1 of "name", whereas another might use a segment such as "name,1.1" to indicate the same. Parameter types may be defined by scheme-specific semantics, but in most cases the syntax of a parameter is specific to the implementation of the URIs dereferencing algorithm.

Solution 4

You cannot type it directly on the browser URL bar.

You can see how POST data is sent on the Internet with Live HTTP Headers for example. Result will be something like that

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

Where it says

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

will be the post values.

Solution 5

The default media type in a POST request is application/x-www-form-urlencoded. This is a format for encoding key-value pairs. The keys can be duplicate. Each key-value pair is separated by an & character, and each key is separated from its value by an = character.

For example:

Name: John Smith
Grade: 19

Is encoded as:

Name=John+Smith&Grade=19

This is placed in the request body after the HTTP headers.

Share:
2,473,155
Camilo Martin
Author by

Camilo Martin

Remember: don't take things too seriously. Especially online.

Updated on October 07, 2021

Comments

  • Camilo Martin
    Camilo Martin over 2 years

    In an HTTP GET request, parameters are sent as a query string:

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

    In an HTTP POST request, the parameters are not sent along with the URI.

    Where are the values? In the request header? In the request body? What does it look like?

    • Mikhail
      Mikhail almost 3 years
      "In an HTTP POST request, the parameters are not sent along with the URI." - though it can be (just theoretically), do not confuse other people. POST, in accordance to spec, MUST serve non-idempotent requests, but you can use request body (which is segregated from Headers by ONE empty line), as well as request parameters.
  • Camilo Martin
    Camilo Martin over 11 years
    "Same format" is a bit ambiguous. Do they begin with an ? for example?
  • SLaks
    SLaks over 11 years
    @CamiloMartin: No; in the same format as the contents of the querystring. See the spec.
  • Peter Wooster
    Peter Wooster over 11 years
    If you want to be really specific, read the RFC: tools.ietf.org/html/rfc2616#page-54
  • Peter Wooster
    Peter Wooster over 11 years
    By the way, this answer is just as good as the other one, it actually says that the values go in the request body. and it provides the W3C spec.
  • Camilo Martin
    Camilo Martin over 11 years
    @PeterWooster Yes, but doesn't provide an example. In that regard, is like an answer that says "look, there's an answer for your question in the application's blog (link)".
  • Camilo Martin
    Camilo Martin over 11 years
    @PeterWooster It isn't needed, but it's very good when you forget something, google it, go to the first link which is SO, and there's a clear, concise example that tells you what you need instead of sending you to chew on the excessively-detailed specs that, even if comprehensive, may be unfit for refreshers. Think about it: most of the QAs on this site could boil down to "go read the spec/manual/API/etc (link)". Would it be useful? Not more than Google.
  • Guffa
    Guffa over 11 years
    Only if the content type is application/x-www-form-urlencoded, which is not always the case.
  • Guffa
    Guffa over 11 years
    Only if the content type is application/x-www-form-urlencoded, which is not always the case.
  • Camilo Martin
    Camilo Martin over 11 years
    I had forgot about file uploads being different (+1/accepted). Your answer is sufficient, while it would be extra nice if it had more info on multipart/form-data. For those interested though, here's a question about it.
  • Devrath
    Devrath over 10 years
    @ Camilo Martin .... [+1] for great question & @ Joe Alfano .... [+1] for great answer ....... i got a clear idea now about the POST request .... but if a image comes along with key,value pair of data information ..... How does the structure of POST looks like ?
  • exhuma
    exhuma over 9 years
    I may have gone on a slight tangent indeed. I added a "tl;dr" to the top of the answer which should make it clearer.
  • exhuma
    exhuma over 9 years
    I also just now edited it to reference RFC7231 instead of RFC2616 (which has been obsolete for a while). The main difference for this answer apart from the updated links, is in the "PUT" section.
  • Pacerier
    Pacerier over 9 years
    @Joe, Now why would you have a From header there?
  • ᄂ ᄀ
    ᄂ ᄀ over 9 years
    The format of GET query string is different from that of application/x-www-form-urlencoded. For example, whitespace is encoded differently (%20 vs +). The answer is misleading in this regard.
  • Tom Howard
    Tom Howard almost 9 years
    @Joe, I love the random inclusion of the From header. IMO it's up there with the 418 HTTP status code.
  • Camilo Martin
    Camilo Martin almost 9 years
    The difference between /user/john and /?user=john is merely a semantic one (HTTP doesn't really give special treatment to query strings), so I take this as reasonably expected. But what do you mean by "wrapped by space on the left"? There aren't spaces before the HTTP method. You mean the blank line for post body?
  • Interface Unknown
    Interface Unknown almost 9 years
    There is a space (ASCII #32) between ...Ym04 and HTTP/1.1 in the above code. So a QueryString simply resides between the verb and the protocol version.
  • Camilo Martin
    Camilo Martin almost 9 years
    Your note makes it sound like it's something unexpected and version-specific. Quite frankly it seems obvious there's a space there. And the line feed also applies to the other lines, like all things unix.
  • Interface Unknown
    Interface Unknown almost 9 years
    I just emphasized what I couldn't mark out in code. It may seem obvious but sometimes it is not.
  • rogerdpack
    rogerdpack over 8 years
    I thought PUT was handled differently than POST since it's supposed to be idempotent? stackoverflow.com/questions/611906/…
  • exhuma
    exhuma over 8 years
    @rogerdpack You are not wrong. If you read the second paragraph in the PUT section, you will see that it is idempotent. POST in contrast can - by definition - not be. POST will always create a new resource. PUT will, if an identical resource exist replace it. So if you call POST 10 times, you will create 10 resources. If you call PUT 10 times, it will (maybe) create only one. Does that answer your question?
  • Gab是好人
    Gab是好人 about 8 years
    NOTE: the body is separated from the header by just one blank line.
  • asgs
    asgs almost 8 years
    It's true that we could pass the query parameters as part of the URL by separating the URI and the parameters with a ? like we do with GET requests.
  • mfaani
    mfaani almost 8 years
    You explained what we place in the HTTPBody, but what do we place/write in the HTTPHeader?
  • mfaani
    mfaani almost 8 years
    You explained what we place in the HTTPBody, but what do we place/write in the HTTPHeader? What purpose does it serve?
  • Guffa
    Guffa almost 8 years
    @Honey: The HTTP header for a post looks like one for a get, but with the verb POST instead of GET, and a content type value (and an optional content length value) as the request has content (body). Every type of request has a header, some types also have a body.
  • Hippo
    Hippo over 7 years
    Clarification: is Content-Length supposed to be 29 here? That's the actual length of the string username=zurfyx&pass=password.
  • Kenny Worden
    Kenny Worden over 7 years
    Can you send JSON using this method?
  • Cholthi Paul Ttiopic
    Cholthi Paul Ttiopic about 7 years
    @KennethWorden No, non of the methods will properly send JSON. you can however upload a json file in a form encoded with multipart/form-data or if you're in charge of request construction, change content-type to application/json and paste json text in http body directly
  • Fabien Snauwaert
    Fabien Snauwaert about 7 years
    As far as encoding is concerned, the MDN docs state the possible values as application/x-www-form-urlencoded (default), multipart/form-data or text/plain (HTML5 only.) Source: developer.mozilla.org/en-US/docs/Web/HTML/Element/…
  • Jinghui Niu
    Jinghui Niu almost 7 years
    You mentioned tha the key can be duplicate, then what is the outcome of such a duplicate? Will the last one will automatically overwrite the previous value(s)? Thanks.
  • vikingsteve
    vikingsteve over 6 years
    @Hippo was a newline character meant to be there?
  • Hippo
    Hippo over 6 years
    @vikingsteve I see what you mean. So I guess the Content always has a newline at the end of it, then.
  • Bipin Chandra Tripathi
    Bipin Chandra Tripathi over 6 years
    @Guffa What about other request types like PUT and delete ? Is this should be used for post requests ? If yes can we have any use case for this query?
  • Johnson
    Johnson over 5 years
    Since the question explicitly states the opposite, it should be mentioned that POST-requests may have URL-encoded query parameters just like GET-requests. Although this might not be common practice this is effectively used: Stanford's CoreNLP tools. In that specific case, the query parameters even contain JSON-encoded values partially related to @KennethWorden 's comment.
  • Mára Toner
    Mára Toner over 5 years
    The header is separated from body with extra newline
  • Ludovic Kuty
    Ludovic Kuty over 5 years
    The answer to the following question is also of interest. application/x-www-form-urlencoded or multipart/form-data?
  • Petru Zaharia
    Petru Zaharia over 5 years
    The assumptions about security are only true in the context of a HTTPS connection, not HTTP. HTTPS encrypts both the URL (including query params) and the Request Body, when HTTP encrypts/protects neither. The issue described comes from the fact that many browsers store the URIs (including URLs) in their history databases (usually not encrypted). So, use only the Request Body+HTTPS for anything sensitive.
  • Zeeshan Adil
    Zeeshan Adil over 5 years
    @PetruZaharia I agree with your explanation. You can also suggest this as edit and I will be happy to accept! :)
  • Hanash Yaslem
    Hanash Yaslem over 4 years
    @JinghuiNiu if the key is duplicate it should be parsed as an array. This is very late but might help someone else.
  • m4l490n
    m4l490n over 4 years
    how do you add a user and password authentication?
  • ToolmakerSteve
    ToolmakerSteve over 3 years
    Expanding on @Guffa's comment: Re "in the same format as the querystring" - that is only correct, if the content type is application/x-www-form-urlencoded. That is the default, but it is not required.
  • Bob Dalgleish
    Bob Dalgleish over 2 years
    How does your answer expand or clarify any of the other answers to this question?