Cross Domain AJAX Guide

As it is widely known, AJAX Requests are only possible if port, protocol and domain of sender and receiver are equal. This means, that the following requests generally won’t work:

  • Requesting https://foo.bar/target.php from http://foo.bar/source.php
  • Requesting http://sub.foo.bar from http://foo.bar
  • Requesting http://foo.bar:5000 from http://foo.bar
Failed remote AJAX

Failed remote AJAX

Having this cleared out, we will cover ways around this restriction.

CORS

CORS stands for Cross-origin resource sharing and has to be supported on the server side. If we take jQuery, the requesting side will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$.ajax({
    type: 'POST',
    url: 'http://d1303.de/remote/cors.php',
    crossDomain: true,
    data: "my_request_is=foo",
    dataType: 'json',
    success: function(responseData, textStatus, jqXHR)
    {
        console.log(responseData);
    },
    error: function (responseData, textStatus, errorThrown)
    {
        console.warn(responseData, textStatus, errorThrown);
        alert('CORS failed - ' + textStatus);
    }
});

Be aware of the crossDomain: true. But take care! This will only work as expected, if the server side sends the appropriate response headers for CORS.

1
2
3
4
5
6
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type');

echo json_encode(array("your_request_was" => $_POST['my_request_is']));

Here, we accept requests from each and every source for the request methods POST, GET and OPTIONS. For more details regarding the various parameters, see this W3C document. For example, you can accept requesting domains like so:

1
2
3
4
5
6
7
8
9
10
11
12
switch ($_SERVER['HTTP_ORIGIN']) {
    case 'http://from.com':
    case 'https://from.com':
        header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
        header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
        header('Access-Control-Max-Age: 1000');
        header('Access-Control-Allow-Headers: Content-Type');
       
        echo json_encode(array("your_request_was" => $_POST['my_request_is']));
       
    break;
}

For more ways to implement CORS on the server side, see enable-cors.org.

CORS

CORS

Browser support is excellent (IE >= 8, Firefox >= 3.5, Chrome >= 3).

JSONP

Let’s move on to the next way of making Cross Domain AJAX possible: JSONP. Like CORS, the server has to support JSONP. Basically, the client tells the server the callback function for the response. The server then wraps the response in this callback function. Example? Example!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$.ajax({
    type: 'GET',
    url: 'http://d1303.de/remote/jsonp.php',
    data: "my_request_is=foo",
    dataType: 'jsonp',
    success: function(responseData, textStatus, jqXHR)
    {
        console.log("the response is", responseData);
    },
    error: function (responseData, textStatus, errorThrown)
    {
        console.warn(responseData, textStatus, errorThrown);
        alert('JSONP failed - ' + textStatus);
    }
});

Let’s look at the request:

JSONP

JSONP

jQuery automatically appends a no cache-parameter with the timestamp and – more interesting – the callback. On the server side, we can now do the following:

1
2
3
4
$callback = $_GET['callback'];
$response = json_encode(array("your_request_was" => $_GET['my_request_is']));

echo $callback . "(" . $response . ")";

This way, the servers response looks like this:

JSONP response

JSONP response

jQuery is now able to invoke the success callback with this information. It is also possible, to specify your own callback with a more readable name, see the $.ajax docs.

As far as I know, there are no browser compatibility issues at all.

iframe

This is more a hack than a “clean” solution. The theory behind this approach is to place a hidden iframe to your requesting page via javascript and then construct a hidden form, that is posting to the iframe. This way, it’s possible to get around the cross domain issue.

The function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function postIframe(target_url, method, params)
{
    //Add iframe
    var iframe = document.createElement("iframe");
    document.body.appendChild(iframe);
    iframe.style.display = "none";
   
    //Give the frame a name
    var frame_name = "frame_name" + (new Date).getTime();
    iframe.contentWindow.name = frame_name;

    //build the form
    var form = document.createElement("form");
    form.target = frame_name;
    form.action = target_url;
    form.method = method;

    //loop through all parameters
    for (var key in params)
    {
        if (params.hasOwnProperty(key))
        {
            var input = document.createElement("input");
            input.type = "hidden";
            input.name = key;
            input.value = params[key];
            form.appendChild(input);
        }
    }

    document.body.appendChild(form);
    form.submit();
}

As we see, a hidden iframe is put on the page. After that, we create a form containing all request parameters as a hidden form field. Finally, the form is programatically sent. We can now trigger the request like this:

1
2
var obj = { my_request_is: "foo", bar: "baz" };
postIframe("http://d1303.de/remote/iframe.php", "POST", obj);

However, there is one big downside: There is no easy way to get the server response from our request, this is more like a “fire and forget” one way-request. If you really want to stick to this approach, here is more info on that.

Other approaches

Even though CORS and JSONP are the most popular methods of doing cross domain AJAX, there are other ways.

  • Take a look at the relatively new window.postMessage (part of the HTML5 feature set) – examples here and here.
  • Another classic approach that is typically taken for this kind of problem is to place a server side script in the language of your choice (e.g. PHP) on your server and request this script via AJAX – which is not a problem, because requesting side and responding side are on the same domain. Your server side script then forwards the request to the remote location and responds back to your script. See the excellent article Building a simple API proxy server with PHP for more details.

Weitere Posts:

Dieser Beitrag wurde unter Javascript, webdev veröffentlicht. Setze ein Lesezeichen auf den Permalink.

8 Antworten auf Cross Domain AJAX Guide

  1. Alex Mano sagt:

    Hi David,

    Very interesting article, thanks for sharing.

    I think there might be a mistake though or I didn’t understood correctly: on CORS you said “For example, you can restrict the requesting domains like so:” and I think it should be “For example, you can ACCEPT the requesting domains like so:”.

    Best wishes,
    Alex

  2. js coder sagt:

    Hi,

    another way to circumvent the Same-Origin-Policy is using the script-tag, for which (to my knowledge) no restrictions apply whatsoever. One can combine that nicely with JSONP, for instance.

    This way, you won’t need to use AJAX, hence you won’t run into any trouble when testing locally without a webserver. Instead of firing an AJAX call, just create and inject a script-element in the page. If you attach event handlers for the onload and onerror-events then you gain the same magnitude of control as if using AJAX.

    I use it frequently, and when you remove the script-element after completion you operate in complete-stealh-mode ;)

    • david sagt:

      Thanks for your comment, I think thats a good substitution for the iframe method. However, you only get the onload and onerror event but other than that no server reponse – like the iframe method.

  3. neel sagt:

    Hi david ,

    very interesting article you wrote . keep it up

  4. Pingback: Руководство по кроссдоменному AJAX`у - Блог Данилова Анатолия

  5. Pingback: Cross Domain AJAX calls | amolshare

  6. ZenCoder sagt:

    Thanks. Have any idea without iframe?

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>