Getting Started With jQuery - Advanced Ajax Transports
Written by Ian Elliot   
Monday, 09 November 2015
Article Index
Getting Started With jQuery - Advanced Ajax Transports
JSONP
Custom prefilter

 

Serverside

At the server the only task is to wrap some JSON in a function wrapper and return the result as if it was a script;

<?php
header("Content-Type:application/javascript; 
                           charset=UTF-8");
$json='{"first": "Ian","last":"Elliot"}';
$cdata="myFunction('".$json."');";
echo($cdata);
?>

If you try this out you will be disappointed to discover that nothing works.

The Ajax then function is never called because jQuery uses a different method to detect the completion of a JSONP request.

When the script is run it attempts to call myFunction with the JSON data but of course there is no myFunction. We can remedy this by adding a myFunction to our client side program: 

function myFunction(data){
 console.log(data);
};

Now when you run the program you will see the JSON string in the console. 

{"first": "Ian","last":"Elliot"}

Again the Ajax request never seems to complete and again this is because we haven't supplied the sort of wrapper function that jQuery expects. 

To know that the JSONP request has completed jQuery has to "know" the name of the wrapper function. 

if you set the jsonpCallback option to the name of the wrapper function 

jsonpCallback

Sets the name of the callback function that the server wraps the JSON data in and is implemented in the client.

For example is you add:

options.jsonpCallback= "myFunction";

then jQuery will hook into myFunction and fire the Promise object's done method when it runs.

Now if you run the program you will see the JSON string twice - once from the myFunction wrapper and once from the Ajax done method. This works no matter which of the two transports is used. 

We can even avoid having to define an explicit wrapper function within the client.

Instead you can get jQuery to pass the name of a suitable wrapper function to the server by simply not specifying a callback. By default jQuery will add a query string callback=long random number. It also creates a callback function with the same random name that simply calls the then method as if an Ajax call had just completed. 

Of course to make this work the server has to add a wrapper function with the name specified by the client - but this is easy:

<?php
header("Content-Type:application/javascript; 
                           charset=UTF-8");
$callback = $_GET["callback"];
$json='{"first": "Ian","last":"Elliot"}';
$cdata=$callback."('".$json."');";
echo($cdata);
?>

All that happens different is that now the server retrieves the query string and uses it as the name of the function to wrap the JSON. Now if you run the client:

var options={};
options.url="process.php";
options.method="get";
options.dataType="jsonp";
$.ajax(options).done(
 function(data){
  console.log(data);
 });

then you will see the JSON data in the console just as if this was a standard Ajax call. 

If you want to take more control of the transaction then you might need to specify the jsonp option to change the name of the query string passed to the server.

jsonp

Set the name of the key passed to the server value of the callback name within the URL.

So for example if the server wants a query string called jsonRequest you can make the client send it using

options.jsonp="jsonRequest";

Now the client will send jsonRequest=some random number to the sever and of course the server has to get the jsonRequest parameter

 $callback = $_GET["jsonRequest"];

You can also stop jQuery sending any callback parameter by setting jsonp to false.

In this case you do need to set jsonpCallback to the name of the callback wrapper function or you have to remember to provide your own function in the client code. 

To summarise:

  • A JSONP request will use XMLHttpRequest transport for a same domain request and a script transport for a cross domain request.

  • If you are writing your own server side code then simply let jQuery generate a name for the wrapper function. Make the server wrap the JSON with a function as specified in the callback parameter and don't implement anything on the clientside. You can treat the whole interaction as if it was an Ajax call with the JSON data delivered to the then method as usual. 

  • If you have to write a client to work with a server that has already been set up to use a specific wrapper name then specify the jsonpCallback option to set the name of the wrapper function that the sever uses. 

  • If the server has been set up to wrap the JSON in a function specified by some other parameter use the jsonp option to specify the name of the parameter. 

A couple of final points.

If you make a cross domain request then script transport is used and you will not get the same range of error handling. 

Cross domain JSONP is an inherent security risk because you are relying on the server not to return any dangerous code.


justjquery

 

 

Custom transport

The idea that jQuery can use different transports to implement an Ajax request is a powerful one. You can add your own transports to jQuery very easily - however implementing the new transport on the server is usually more difficult. 

To add a new transport to jQuery all you have to do is use the ajaxTransport method. 

ajaxTransport(dataType,handler)

Add a new transport method for the named data type. 

The only complicated part about ajaxTransport is that the function that you specify as the second parameter doesn't implement the transport it simply returns an object that does i.e. it is a transport object factory.

The definition of the transport object factory is:

function(options,originalOptions,jqXHR)

where options are the request options including any defaults, originalOptions are the options explicitly set by the user and jqXHR is the jqXHR object constructed for the request.  The jqXHR object has a lot of additional information about the request including the url etc. 

The transport object factory has to return a transport object which has just two methods send and abort:

send :function(headers,completeCallback)

This just has to implement the transport and call completeCallback when the transport is completed. It can use the headers passed into the function as necessary.

abort :function()

This simply has to abort the transport - which is often easier said than done!

The final function to define in this set is completeCallback:

function(status,statusText,responses,headers)

Where status and statusText give the reponse code and text, responses is a set of dataType key value pairs i.e. it is the payload of the transport and headers is again a set of optional response headers.

Let's implement the simplest example of a new transport which returns a fixed string immediately.

The transport object factory is:

function myTransportFactory(options,
                  originalOptions,jqXHR){
 var transport={
   send:function(headers,callback){
         callback(200,"success",
          {mydatatype:"this is the data"});
        },
  abort:function(){
        }
  };
 return transport;
}

Notice that all this does is to construct an object with two properties send and abort. The send function calls the callback function to signal that it is complete at once. It sends back the success status code and text and the data "this is the data". Notice that the data type has to be the type that the transport is designed to handle otherwise a converter will be called. 

To register the new transport all we have to do is:

$.ajaxTransport("mydatatype",myTransportFactory);

The entire program is:

$.ajaxTransport("mydatatype",myTransportFactory);
var options={};
options.url="process.php";
options.method="get";
options.dataType="mydatatype";
$.ajax(options).then(
 function(data){
  console.log(data);
});

In this case the url and the method are fairly irrelevant. Notice that the datatype has to be mydatatype. If the transport returns alternative data types then you might need a converter. If you run the program you should see "this is the data" in the console. 

Now that you have seen a simple example you are probably wondering what sorts of things you could implement using a custom transport. The first thing to notice that that you could use the simple example as a testing harness for Ajax programs so it isn't completely useless. 



Last Updated ( Thursday, 05 May 2022 )