Introduction
In this modern era of jaw-dropping web technologies and business shifting their marketing concerns to the web, we see more than a dozen of websites involving huge amounts of data exchange between the client and the server.
Newer web applications are utilising enormous scripts and an array of network roundtrips to tailor content for their users and provide them with a smooth interface to interact with. Large forms and surveys are being shifted to online portals, with sophisticated architecture and tedious coding.
It is now possible to upload files to servers from webpages, check out from online stores, perform online banking and much much more on this road.
Part of this involves being able to send data from the client to the server easily and safely using the POST method. POST, as we'll discover in this chapter, has a couple of interesting advantages over the traditional GET method due to which it enjoys the position of being an active part of the recent possibililty diagram of the web.
Limitations of GET
As we saw in the previous chapter on AJAX Request Methods, there are a couple of methods to send out an HTTP request. The method determines the way data is sent within the request and tailors the action that happens with it on the server.
GET
as we all know, is the most common and most basic of all request methods out there. It asks a server to simply get a given file and throw it back.
GET
requests can also be used to send data to a server by appending a query string next to the URL. However there are certain limitations to sending data in this way.
Limited data allowed to be sent
First of all there is a prescribed size limit to query strings beyond which we can't send any further data within them. Each browser has its own implementation of this size; but nonetheless the point is that there is some limit. This means that GET
fails to win in the case when we want to send large amounts of data in the request.
Is unsafe
Moving further, all the data in a GET
request is part of the query string which is a part of the URL. In other words, all our data is visible in the URL of the webpage.
As you'll appreciate, this is particularly undesirable for sending sensitive data such as passwords or credit card numbers to a server - you'd never want these bits of informations to appear in any URLs, would you? This means that we can't use GET
, at any cost, when we ought to send sensitive form data across the network.
Lastly, extending these two limitations about GET
, this method isn't convenient at all to send file data in the request. The data will usually cross the length limits of the URL and thus prevent any data interchange between the client and the server.
Owing to these problems with GET
, the above use cases are instead solved using the request method POST
.
Exploring POST
GET
is not solely meant to send data from a client to a server. It's definitely used to do so, but the point is that this isn't its purpose.
Rather GET
is used to request a server for a given file. For example, when we visit www.example.com/home.html
, a request is made to the server of www.example.com
, to fetch home.html
.
Here, we aren't sending any data in the GET
request, but rather just requesting for it.
The POST
method is the complete opposite of this:
POST
is meant to literally post data to a server i.e send data to it.It is a standard for sending complex and sensitive data to the server, with the additional capability of sending as much data as the need be.
There is no limitation, whatsoever, to sending data in a POST
request. It's all upto you!
Exploring the layout of a POST
request, we see that it comprised of three things: a request line, followed by a block of headers, (followed by a line), and finally a request body.
Let's dissect a POST
request in detail...
Dissecting a POST request
Following is the general form of a POST
request:
<request-line>
<headers>
<request-body>
First we have a request line which contains the method of the request, followed by the file path after the host name, followed by its HTTP version of the request.
The we have the headers of the request, each on a newline, giving further information about it such as its Host
, User-Agent
and so on.
After this comes a blank line and finally the body of the request. Each time you dispatch a POST
request, all its data goes here (after the blank line).
Consider the snippet below showing a POST request made to the file foo.php
at the URL www.example.com/foo.php
:
POST /foo.php HTTP/1.1
Host: www.example.com
Content-Length: 9
Content-Type: application/x-www-form-urlencoded
User-Agent: ....
msg=Hello
In the first line, POST
is set as the request method, and then the file path of the request (the string after the hostname) is specified. HTTP/1.1
simply tells that the request is of HTTP version 1.1 - successor to version 1 and predecessor to version 2.
Then we have some headers following, described below:
Host
holds the hostname of the request's destination URL. In most cases, and as limited by the cross-origin policy, this is usually the same hostname that is of the webpage making the request. This is used to figure out a fully qualified URL of the requested page - by appending the file path to the hostname.Content-Length
specifies the byte-length of the request body i.e size of the data in bytes.Content-Type
is the most important of all and specifies the encoding type for thePOST
request. We'll explore it in detail shortly below.User-Agent
holds information about the browser that dispatches the request. It's a long, tedious string of characters; and likewise we've omitted it here to keep things clean and simple.
After all this, we have a blank line and finally the request body containing the data msg=Hello
. The way this data is represented in the request differs, depending on the value of Content-Type
. We'll see the details to this later in this chapter.
Posting data with AJAX
With a solid understanding of how a POST request looks internally, it's now time to see how to combine it with AJAX.
Let's start by evaluating your thinking skills.
What is the first step we need to take in order to send out a POST request in AJAX?
- Call
send()
and supply it data of the request. - Set respective headers for a
POST
request. - Call
open()
and change its first argument to"POST"
.
First of all we'll need to set open()
's first argument to the value "POST"
. This determines the method for sending out the AJAX request.
Then to send data in the request body we have to supply a value to the method send()
.
What this method does is that it simply takes its argument, does the neccessary serialization it needs to do on it, and finally appends it to the body of the request, thus completing a POST fetch.
But before we can do this, we have to specify the encoding type of the data. This is essential to be able to smoothly work with the POST data on the server end.
The way we do this is by specifying the Content-Type
header and giving it one of the following three values:
text/plain
application/x-www-form-urlencoded
multipart/form-data
The first value text/plain
is the default if we don't specify a value for Content-Type
explicitly. It's the least used and least useful of all these three content types, however, regardless of this fact we'll show you the way to deal with data sent using it, back at the server.
The second value, and perhaps the most frequent value for Content-Type
, application/x-www-form-urlencoded
, simply tells that the request body is url-encoded. The syntax of the request body in this case is similar to the syntax of query strings in GET requests.
The third and last value, multipart/form-data
is used to deal with the cases where files have to be sent within the request. It operates quite differently than application/x-www-form-urlencoded
, using boundaries to match up different data parameters with their corresponding values.
Let's take a closer look at each value...
text/plain
The encoding type text/plain
trivially sends out the request body as is - it is sent as plain and simple text.
If we omit the Content-Type
header while sending a POST
request using AJAX, text/plain
is the default value the header is given.
Sending POST
data with this encoding type is least preferred for various reasons - one being that the name-value pairs in the request body aren't parsed by PHP. This makes it quite difficult, inefficient and tedious to handle client-side data at the backend.
$_POST
array to fetch the values of different parameters in the request. However for text/plain
encoding, this array remains unfilled.Consider the example below that sends some plain textual data to the server which then outputs it using the input stream, as it is:
var xhr = new XMLHttpRequest();
xhr.open("POST", "post-data.php", true);
xhr.onload = function() {
if (this.status == 200) {
alert(this.responseText);
}
}
xhr.send("msg=Hello World");
<?php
echo file_get_contents("php://input"); // read from standard input
?>
application/x-www-form-urlencoded
The encoding type application/x-www-form-urlencoded
hints the server that the request's body is in url-encoded format i.e all name-value pairs are encoded.
When constructing an HTML form with the attribute method
set to "POST"
, the default encoding type for sending the data of the form is application/x-www-form-urlencoded
.
The body of a POST request with this encoding type has the following general syntax:
name1=value1&name2=value2
Each pair is separated by an ampersand &
sign and within the pair, the name and value is separated using an equals =
sign. As you can see, this general format is the same as the one for constructing URL query strings.
In most cases, you'll be more than just well off with encoding your POST data using application/x-www-form-urlencoded
.
It is both:
- Parsed by PHP, unlike
text/plain
. - Slightly more performant than
multipart/form-data
(the third encoding type as we shall see next).
Consider the following example:
var xhr = new XMLHttpRequest();
xhr.open("POST", "post-data2.php", true);
xhr.onload = function() {
if (this.status == 200) {
alert(this.responseText);
}
}
xhr.send("msg=Hello+World");
<?php
echo $_POST["msg"]; // output the parameter value of msg
?>
Here we compose a very simple POST request, set its Content-Type
to application/x-www-form-urlencoded
, using the setRequestHeader()
method, and finally write its response to the document once complete.
$_POST
variable only works for the encoding types application/x-www-form-urlencoded
and multipart/form-data
!You are given an input element and the task to post its value to the script search.php
, once it loses focus i.e it becomes blur.
The server script at the backend is configured to read this value from the parameter query
and use it to perform a search operation in a database. This means that the data in the request is sent as query=inputValue
.
For simplicity, the element's onblur
event has already been assigned the following handler function, but without any function body:
function sendRequest() {
// handle the onblur event
// write your code here...
}
// imagine the line below has been set
// input.onblur = sendRequest
Complete this function such that it creates a new AJAX POST request and sends it to the server along with supplying the value of the input element.
onreadystatechange
to track the state changes of the request. Once it's complete and returns with a 200 OK
status, you shall pass responseText
to alert()
. Also take care of any encoding you need to perform in this task!Since the server needs to read the input value from the parameter query
, the best way to send this data is using application/x-www-form-urlencoded
(which is parsed by most servers).
With this decided, the next thing we see here is that the value from the input element shall be encoded before being put in the request body. Recall from the AJAX Request Methods chapter, that the function encodeURIComponent()
serves this job.
Likewise, following is the complete definition of the handler function:
function sendRequest() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "search.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
}
}
xhr.send("query=" + encodeURIComponent(this.value));
}
multipart/form-data
The encoding type multipart/form-data
, as we've been saying for so long, is used to handle file data transmission in the request. It works pretty much like application/x-www-form-urlencoded
, but with the additional concept of boundaries.
In the Content-Type
header of the POST request, first we have the value multipart/form-data
and then after it a semi-colon ;
and finally a string of the following form: boundary=someRandomValue
.
This denotes a boundary for delimiting different segments of the data within the request body.
Consider the following snippet showing an example of a multipart/form-data
POST request with a parameter msg
of value "Hello"
:
POST /foo.php HTTP/1.1
Host: www.example.com
Content-Length: 63
Content-Type: multipart/form-data; boundary=XYZ
--XYZ
Content-Disposition: form-data; name="msg"
Hello
--XYZ--
Notice a couple of things over here:
- The value of
Content-Type
is a bit different than what we've been seeing so far - first we have the encoding type and then a boundary value, which in this case is equal toXYZ
. This boundary value is used inside the request body to be able to separate the data within it, easily. - The request body begins with a line containing two hyphens and then the boundary value. This is the syntax of all multipart encoding types i.e each boundary line is prefixed with a set of two hyphen characters.
- The
Content-Disposition
header gives us further information about a specific data parameter i.e does it hold data of a file or simply a form input. It even holds the name of a parameter given using thename
directive. In this case the header tells us thatmsg
holds simple form data. - After this comes a blank line and then finally the value of the parameter.
- At the end we once again have a boundary line (beginning with
--
and followed byXYZ
), but this time also suffixed by two hyphens, since it denotes the end of the body.
The request body is comprised of the lines 6 - 10, which means that in order to send this request using AJAX, we'll have to supply this whole value to the send()
method as a string.
Following is a simple example, utilising template literals to easily create a string for the request body:
var xhr = new XMLHttpRequest();
xhr.open("POST", "search.php", true);
// set the Content-Type header along with setting a boundary value
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=XYZ");
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
}
}
// the request body created using template literals
xhr.send(`--XYZ
Content-Disposition: form-data; name="msg"
Hello
--XYZ--`);
multipart/form-data
and handling files in AJAX!