a simple example of jquery, ajax.post, and php

I’ve learned enough about ajax, from javascript ajax to jquery ajax, from client side to server side, from asp to php, from form submit to various data types encoding and decoding. But like jquery selectors, if I do not write ajax code for some days, I’ll forget them all. So, I decide to write a minimum ajax code here using jquery and php as a memo.

send string

$.post("http://myprogrammingnotes.com/test.php","abc",function(result){alert(result);});

This piece of code sends a string “abc” to the server script:http://myprogrammingnotes.com/test.php. How to get that data in the script on server? If you try to print that data using “print_r($_POST);”, you will find it prints an empty array. The correct way to get the raw data is:

echo file_get_contents("php://input");

The raw data is all the bytes after the http headers to the end of the http payload. If the string passed to the server has this form:”par1=var1&par2=var2″, the $_POST array on the server side can be generated successfully, and “print_r($_POST);” will print the array elements without problem. There are two elements in the $_POST array:par1=>var, par2=>var2;

send object

After said in the official document of jQuery, the second parameter of $.post can not only be a string but also be an object.

$.post("db.php",{par1:"123"},function(result){alert(result);});

Now the data to be sent is a simple object with single member. This member “par1″ is a string “123”. On server side, the $_POST array can be generated without problem, which has one array element:”par1″=>”123″. Note that both the key and the value of the element are strings. If the ajax call is changed to:

$.post("db.php",{par1:123},function(result){alert(result);});

i.e.,the object member is now changed to an integer, how does the element of $_POST look like? Is it changed to “par1″=>123, i.e., the value of the element becomes an integer? No! It keeps “par1″=>”123″. In fact, the payload of the http is not changed at all: par1=123. If the data is not a string in $.post, it will encode the data to a string of the form “par1=var1&par2=var2…”. This is so called url encoded string and the content type in the http header is set to “application/x-www-form-urlencoded”. While php module on the server side decodes the “application/x-www-form-urlencoded” content, all the key,value pairs are decoded to string=>string elements in $_POST.

successful and failed ajax call

Note that only the url parameter is necessary, the other parameters are optional. The third parameter is a function to be called when the ajax call is successful. What is a successful ajax call? It does not depends on what is received from the serer but the http code returned from the server. “200 ok” results in a successful ajax call while “404 not found” indicates the call was failed. 3xx redirection can also result in successful ajax call as long as the final destination returns 200 ok. If you use the ajax to fetch an http url in an https  script, the call would fail with the error:”Blocked loading mixed active content …” No packet will be sent to the server. The call fails locally. Cross-domain ajax call(i.e., you post to a domain other than the domain your script resides on) will also fail but the POST http request will be sent to the remote server. The error is as follows:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://myprogrammingnotes.com/test.html. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)

There is no parameter to be used as a callback to catch the failure information for failed ajax calls.

The other form of $.post

The official jQuery document says $.post has another form:$.post(settings), where settings is an object as in $.ajax. But it is not correct. If you write the following code:

$.post({url:"https://myprogrammingnotes.com",data:"mydata"});

the object as the parameter would be converted to a string that is used as the url for the ajax call. Of course,the url is usually wrong and the ajax call would fail. I’ve tried the following $.post form:

$.post("https://myprogrammingnotes.com",{data:"data",success:function(data,status,xhr){alert(data);}});

The call was successful but did not get the expected result. I intended to pass the setting object as the second parameter but the call converts the second parameter to a data string  and passes it to the server. However, the settings object is somewhat accepted because the success callback is invoked later. So I think it is a jQuery bug and you should avoid to use this type of $.post.

send binary data

To have more control over the ajax call, you should use $.ajax instead of $.post. You can pass a settings object to $.ajax to customize its behavior. For example, you may want to send binary data to server instead of strings. You should not use the following code:

$.ajax({url:"http://myprogrammingnotes.com",type:"post",data:123,contentType:"application/octet-stream",success:function(data,status,xhr){alert(data.char);}});

The data cannot be accepted so discarded. The request body of the http post will be empty and the content-length in the http header is set to 0.

You may think of using:

$.ajax({url:"http://myprogrammingnotes.com",type:"post",data:123,contentType:"application/octet-stream",processData:false,success:function(data,status,xhr){alert(data.char);}});

i.e., set processData to false to avoid to encode the data. However, the integer data is still encoded to string “123”(3 bytes), not a byte (0x7b).

The correct way to post binary data using jquery ajax is using typed array:

var bytesToSend = [123],
bytesArray = new Uint8Array(bytesToSend);
    $.ajax({url:"http://myprogrammingnotes.com",type:"post",data:bytesArray,contentType:"application/octet-stream",processData:false,success:function(data,status,xhr){alert(data.charCodeAt(0));}});

Now the body of the request has only one byte(0x7b). Note that you still need to set processData to false, otherwise, the array would be encoded to “0=123″(5 bytes).

send JSON string

You can see transferring raw binary data from client to server using ajax is not an easy thing to do. You must populate the binary data to a typed array, then set the correct values of contentType and processData. But passing a javascript object to server is common task. We usually achieve that by encoding the object to a JSON string, passing the json string to server, then decoding the json string at the server to construct the corresponding object.

As said at the beginning of this post, the string data will be sent to the server as is if it is not of the form “par1=var1&par2=var2…”. So we can safely pass the JSON string to the server using:

var data={par1:"var1",par2:"val2"};
$.ajax({url:"http://myprogrammingnotes.com/",type:"post",data:JSON.stringify(data),success:function(data,status,xhr){alert(data);}})

The request keeps the same with or without “processData:false”.
Now, we know how to pass the JSON string to the server. But how to decode the JSON string to get the object at the server side? We can get the raw POST data and decode it to an object as follows:

$obj = json_decode( file_get_contents( 'php://input' ));

The JSON deliver and decoding scheme works but is not perfect. The http request still has an “application/x-www-form-urlencoded; charset=UTF-8″ Content-Type, which will trigger the parsing and the decoding of the request body to $_POST at the server side, and this is not we expect. If the javascript object is:

var data={par:"par1=var1"}

, the $_POST will be

Array
{
    [{"par":"par1]=>var1"}
}

We does not actually want to produce a $_POST array if we post a JSON string. We can suppress the generation of $_POST by using the “application/json” Content-Type in the http headers.

var data={par1:"var1",par2:"val2"};
$.ajax({url:"http://myprogrammingnotes.com/",type:"post",data:JSON.stringify(data),contentType:"application/json",success:function(data,status,xhr){alert(data);}})

This way, the $_POST at the server side would be an empty array.

decode response

We’ve almost covered everything on sending data using jQuery’s ajax functions. It is time to turn to the response got from the server. Let’s continue with the above example. The following php code at the server will echo the JSON string to the client.

<?php
echo file_get_contents("php://input");

 

Now we want to display the object’s property par2.

var data={par1:"var1",par2:"val2"};
$.ajax({url:"http://myprogrammingnotes.com/",type:"post",data:JSON.stringify(data),contentType:"application/json",success:function(data,status,xhr){alert(data.par2);}})

But why does it display “undefined”? Well, although the content returned from the server is a JSON string representing a javacript object, the data parameter of the “success” callback function is still a string because the http response has a “text/html; charset=UTF-8″ Content-Type, based on which jQuery interprets the content as a string and passes it as the data parameter.  Of course you can create the js object from the JSON string manually using JSON.parse. But jQuery can make things easier. First, you can change the server code to alter the Content-Type header before sending the JSON string.

<?php
header('Content-Type: application/json');
echo file_get_contents("php://input");

Now jQuery tells the content is JSON from the Content-Type header of the response, so parses the returned content to a js object and pass the object to the “success” callback.
If you can not modify the server code, you still have the ability to force jQuery to treat the returned content as JSON and parse it to a js object by using the dataType parameter in the request.

var data={par1:"var1",par2:"val2"};
$.ajax({url:"http://myprogrammingnotes.com/",type:"post",data:JSON.stringify(data),contentType:"application/json",dataType:"json",success:function(data,status,xhr){alert(data.par2);}})

Now even the response has a “text/html; charset=UTF-8″ Content-Type, jQuery will consider the response body as JSON and do the proper decoding. Note that unlike the contentType parameter, the dataType parameter is not an http request header, nor is encoded into a request header to be sent to the server. dataType only makes sense at the client side, i.e., tells jQuery library to decode the returned content to form the proper parameter for the “success” callback.

Comments are closed, but trackbacks and pingbacks are open.