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:

$.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.

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:

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!

$.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:

$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:

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:

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.

Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0