Cross-Domain AJAX?

May 22, 2008

Imagine you have a web site that uses some data from a server. Imagine you want to get the data from this server without refreshing the web site. Finally, imagine that your site is not hosted on the server it gets data from (the server and the web site have different domains). Well, you have a problem. First, I apologize. This will, probably, be a very technical article. However, I also think that the content is quite valuable.

Motivation

Stankaa, my web project, is based on the idea that anybody can add her to his/her web site. You just have to copy 2 lines of code to your web site and it works.

All of this is done using XHTML Strict and without any <iframe> elements. The web site never reloads. Stankaa gets the information she needs from the stankaa.com server asynchronously and modifies the host web site on the fly. The usual way of doing such things is using the XMLHttpRequest JavaScript object (the AJAX way). The problem is, it just doesn’t work if you are requesting information from a different server than the one your site is hosted on. Since the whole idea behind Stankaa is that she can be included in anybody’s web site, I had to come up with a solution.

Ajax

First, I will show you how it is usually done when you do not want to do it cross-domain.

function ajax_request(send, onReady)
{
    var request = window.ActiveXObject
        ? new ActiveXObject("Microsoft.XMLHTTP")
        : new XMLHttpRequest;

    request.onreadystatechange = function()
    {
        if (request.readyState != 4) return;
        onReady(request.responseText);
    }
    request.open("POST", "http://some-domain.sk/some.php", true);
    request.setRequestHeader("Content-Type",
                             "application/x-www-form-urlencoded");
    request.send(send);
}

This is a source code of a simple function that can “do” AJAX requests for you. You do not have to understand how it works. I will just explain how you can use it. Try something like this:

function onAnswer(answer) { window.alert(answer); };
ajax_request("", onAnswer);

What does it do? The ajax_request function makes a POST request for “http://some-domain.sk/some.php”. When the server answers, the onAnswer function you provided as a parameter for ajax_request executes. It displays an alert window showing the server answer. All this happens “in the background”, and the web page doesn’t reload (thats the point!). You can provide POST parameters for the target .php like this:

ajax_request("pudding=christmas&state=burned", onAnswer);

Of course, since JavaScript support anonymous functions (which is a really really nice feature that works especially well with closures in JavaScript), you can write just:

ajax_request("pudding=christmas",
             function (answer) { window.alert(answer); });

How to do it cross-domain

All above should work as long as you request the .php file which is located on the same domain as the requesting web site is. However, it doesn’t work for Stankaa’s scenario. After a few hours of desperate research, I managed to put together something that works the way I need it to. Although I must admit that the basic idea behind this thing isn’t mine (dynamically adding a <SCRIPT> sub element to <HEAD> to get server data), I collected the information from many sources and packed it inside this “lovely” package:

request_callback = undefined;

function request_send(send, callback)
{
    request_callback = callback;
    request_script = document.createElement("script");
    request_script.src = "http://some-domain.sk/some.php?" + send;
    document.getElementsByTagName("head")
        [0].appendChild(request_script);
}

function request_receive(data)
{
    document.getElementsByTagName("head")
        [0].removeChild(request_script);
    request_callback(data);
}

The usage of the request_send() function remains the same as for the ajax_request() function. Request_send(), is, however, capable of doing a cross-domain asynchronous server request. Since it doesn’t use the XMLHttpRequest object, I’m not sure if I can call it “Ajax” anymore.

This approach has its limitations. The first limitation is, POST method is not supported. Everything you specify in the “send” variable will appear in $_GET array in PHP. The second limitation is, the server-side PHP has to “cooperate”. What does it mean? It means that instead of doing

<?php echo "I am a Christmas Pudding!"; ?>

the PHP file has to do this:

<?php echo "request_receive('I am a Christmas Pudding!');"; ?>

But, I don’t think thats such a big problem.

Finally, I will briefly talk about how it works. When you call the request_send() function, JavaScript adds new <SCRIPT> element to document <HEAD> element. This new script tag specifies the requested PHP file as its source (”src”) attribute. The PHP file is then automatically requested. When the request (in form of a “request_recieve(’I am a Christmas Pudding!’);” source code) arrives, its content is executed. Consequently, request_receive() function is called, the <SCRIPT> element is removed from the document head and user-defined callback function is executed with a data that server sent.

The really great thing about this is that it works across all major browsers (latest Opera, Safari, Firefox, IE7 and IE6). And the funny thing is, many people believe that it can’t be done at all :) Some people have already found this way of doing it, by I doubt it is a widespread phenomenon.

Full article here

 

Post a comment

Name (required)

Mail (will not be published) (required)

Website

*
To prove you're a person (not a spam script), type the security text shown in the picture. Click here to regenerate some new text.
Click to hear an audio file of the anti-spam word