jQuery and Crossdomain

Posted on 1/7/2012 @ 1:58 PM in #Azure by | Feedback | 4990 views

There seems to be a tonne of misguidance on this topic, mostly driven by older jQuery versions. Unfortunately this guidance seems to show up a lot in Azure + SharePoint integration conversations, so I thought, there is always time for a quick rant blog post before I board my flight (in 2 hours, and haven’t packed my bags yet!).

So, here is the deal! Things changed in jQuery 1.5, as quoted from - http://api.jquery.com/jQuery.getJSON/

As of jQuery 1.5, the success callback function receives a "jqXHR" object (in jQuery 1.4, it received the XMLHttpRequest object). However, since JSONP and cross-domain GET requests do not use XHR, in those cases the jqXHR and textStatus parameters passed to the success callback are undefined.

Another issue of course is, such cross-domain requests are inherently insecure. Either you are sending credentials over clear text, OR, you cannot make cross-domain requests (not without an ugly client side warning atleast) on HTTPS.

So how do we make cross-domain requests work with jQuery? Now, as you know, $.get and $.getJSON use $.ajax. Since jQuery 1.5, there has been a new property added to $.ajax. It’s called ‘crossDomain’.

crossDomain:
Default:
false for same-domain requests, true for cross-domain requests
If you wish to force a crossDomain request (such as JSONP) on the same domain, set the value of crossDomain to true. This allows, for example, server-side redirection to another domain.

Source: http://api.jquery.com/jQuery.ajax/.

The server side redirection is quite simple to do in PHP, as shown below,

  1: $data = '{"name" : "hello world"}';
  2: echo $_GET['jsoncallback'] . '(' . $data . ');';

You can also use YQL (Yahoo Query Language) to perform such server side redirection as shown below,

  1: jQuery.ajax = (function (_ajax) {
  2:     var protocol = location.protocol,
  3:         hostname = location.hostname,
  4:         exRegex = RegExp(protocol + '//' + hostname),
  5:         YQL = 'http' + (/^https/.test(protocol) ? 's' : '') + '://query.yahooapis.com/v1/public/yql?callback=?',
  6:         query = 'select * from html where url="{URL}" and xpath="*"';
  7: 
  8:     function isExternal(url) {
  9:         return !exRegex.test(url) && /:\/\//.test(url);
 10:     }
 11: 
 12:     return function (o) {
 13:         var url = o.url;
 14:         if (/get/i.test(o.type) && !/json/i.test(o.dataType) && isExternal(url)) {
 15:             o.url = YQL;
 16:             o.dataType = 'json';
 17: 
 18:             o.data = {
 19:                 q: query.replace(
 20:                     '{URL}',
 21:                     url + (o.data ?
 22:                         (/\?/.test(url) ? '&' : '?') + jQuery.param(o.data)
 23:                     : '')
 24:                 ),
 25:                 format: 'xml'
 26:             };
 27:             if (!o.success && o.complete) {
 28:                 o.success = o.complete;
 29:                 delete o.complete;
 30:             }
 31: 
 32:             o.success = (function (_success) {
 33:                 return function (data) {
 34:                     if (_success) {
 35:                         _success.call(this, {
 36:                             responseText: data.results[0]
 37:                                 .replace(/<script[^>]+?\/>|<script(.|\s)*?\/script>/gi, '')
 38:                         }, 'success');
 39:                     }
 40:                 };
 41:             })(o.success);
 42:         }
 43:         return _ajax.apply(this, arguments);
 44:     };
 45: })(jQuery.ajax);
 46: 
 47: function InitializeWebPart() {
 48:     $.get('https://someotherURLCrossDomain', function (data) {
 49:         $("#results").html(data.responseText);
 50:     });
 51: }

Writing a web role in Azure to do server side redirection is also quite trivial.

Few other notable points about cross domain ajax requests using jQuery -

  • The error handler won’t get called on such requests.  $.ajaxSend and $.ajaxError cannot be used with such requests.
  • You can secure such requests by using xhrFields { withCredentials: true }
  • You cannot make such requests synchronously.
  • Get requests are a matter of making a simple call. PUT/POST/DELETE/MERGE verbs need an additional handling especially for security. There is an ‘OPTIONS’ verb sent before those other verbs can be called.

Gotta run!

Sound off but keep it civil:

Older comments..