Cross-domain AJAX with jsonp
I have a web page on domain A and, say, a Json endpoint on domain B. I would like domain A to make an Ajax request to domain B, but when I try that, I get an error message, as shown here:
$(document).ready(function() { | |
$.ajax({ | |
type: "GET", | |
url: "http://www.google.com", | |
dataType: 'json', | |
crossDomain: true // forcing a cross domain request for demonstration, you can omit this | |
}) | |
.done(function(content) { | |
console.log(content); | |
}); | |
}); | |
// should result in error message: | |
// XMLHttpRequest cannot load http://www.google.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. |
Some options:
- Make the request server-side instead of client side.
- If you have control of the endpoint, add "Access-Control-Allow-Origin" to the response header.
- Use jsonp (you may still need control of the endpoint if it doesn't support jsonp already).
Let's explore the jsonp option. Here's a similar request to the one above, except this time it's using jsonp.
$(document).ready(function() { | |
$.ajax({ | |
type: "GET", | |
url: "http://exampleapi.com/jsonp", | |
dataType: 'jsonp', | |
crossDomain: true // forcing a cross domain request for demonstration, you can omit this | |
}) | |
.done(function(content) { | |
console.log(content); | |
}); | |
}); |
It does not raise an error.
The way jsonp works is a little wacky, but the main thing you need to know is that you need to specify a callback function. jQuery handles this automatically on the client side. Here's how I handle it on the server side with ASP.NET MVC using the Mvc.Jsonp package.
using System; | |
using System.Net; | |
using System.Web.Mvc; | |
using Mvc.Jsonp; | |
namespace My.Controllers | |
{ | |
[AuthFilter] | |
public class SomeController : JsonpControllerBase | |
{ | |
public JsonpResult GetAllItems(string callback) | |
{ | |
var items = MyItemRepository.GetAllItems(); | |
return Jsonp(items, callback, JsonRequestBehavior.AllowGet); | |
} | |
} | |
} |
Notice three things:
- SomeController inherits from JsonpControllerBase
- GetAllItems return type is JsonpResult and has a "callback" string parameter
- The Jsonp function from the base class and how callback is passed to it.
The benefit is that you can now do cross-domain scripting. So far the drawbacks seems to be that:
- It's limited to GET requests
- Error handling may take some extra work
- If there is no Jsonp endpoint, then you either have to make one or you're out of luck.
I'm giving it a shot on Ledger, and seems to be working fine so far.