I have a large amount of static/rarely changing data in JSON format. To improve my ASP.NET MVC application performance, I would like to move them to a CDN (Amazon Cloud Front).
However when I do that, the cross domain policy kicks in and jQuery makes a HTTP OPTIONS method call instead of HTTP GET and Amazon denies the requst with "403 Forbidden" response.
JSONP might be a way around this but since the files are static and on a CDN there is no way to wrap the JSON in a custom function. However I can recreate them wrapped with a known function name. For example:
{"LineDetails":{"LineNo":"3109","DbId":9 ....}}
I can do something like:
JsonWrapping({"LineDetails":{"LineNo":"3109","DbId":9 ....}});
The "JsonWrapping" function name will be the same for all the files.
Is it possible for jQuery to download JSON data via JSONP if it is wrapped in the same function name as shown above? My reading of jQuery JSONP is that jQuery creates some custom one time use function name for the JSONP request. Can this be overridden?
Thanks for your help.
In the docs for $.getJSON
and $.ajax
, the jsonp section notes that you can set the callback function name explicitly with the jsonpCallback
config property. So if you want JsonWrapping(...)
to be the function jquery expects inside of the jsonp response, you can tie things back up like so:
$.ajax({
url: 'http://blah.com/blah.json',
dataType: 'jsonp',
cache: true,
jsonpCallback: 'JsonWrapping'
})
.done(function(r) {
status.text('It worked.');
})
.fail(function (a, b, c) {
status.text('It failed.');
});
In the above example the expected callback function inside the jsonp response is now JsonWrapping()
, which jQuery will emit for you, respond to by calling .done()
above, and cleanup after itself - much cleaner than hard-coding JsonWrapping
into the page.
An important thing to consider is if you plan to have many jsonp calls on a single page, and your jsonp wrapping functions are hard-coded in the jsonp files, you should at least vary your wrapping function by something, like filename. Otherwise you create an asynchrony problem. For example assume you had this code:
function jsonp(url) {
return $.ajax({
url: url,
dataType: 'jsonp'
cache: true,
jsonpCallback: 'JsonWrapping'
});
}
jsonp('http://cdn.mine/one.jsonp')
.done(...);
jsonp('http://cdn.mine/two.jsonp')
.done(...);
One of these jsonp calls is going to finish before the other - it's impossible to know which - and jQuery is in an impossible situation where it can't know which .done()
to call for which response. As a result you'll get some page loads where they're called correctly, and some where the data crisscrosses. The solution is to vary by something like filename, like:
function jsonp(url, wrapper) {
return $.ajax({
url: url,
dataType: 'jsonp'
cache: true,
jsonpCallback: wrapper
});
}
jsonp('http://cdn.mine/one.jsonp', 'one')
.done(...);
jsonp('http://cdn.mine/two.jsonp', 'two')
.done(...);
So the response from two.jsonp would need to look like:
two({...json object here...})
The call at the beginning of this answer will make jQuery request the URL via GET like this:
http://blah.com/blah.json?callback=JsonWrapping
And expect this as the response:
JsonWrapping({...object here...})
I included cache: true
above because this is on a CDN, and so, presumably is not meant to change very often. If you leave cache: true
out, jQuery inserts a second querystring param meant for cache-busting, like:
http://blah.com/blah.json?callback=JsonWrapping&_=1365175172440
Which can ruin the point of a CDN. The goal of the second querystring parameter is to ensure the data isn't loaded from the browser cache, and, when it hits the server (the CDN in this case), the querystring is unique meaning it busts its cache as well.
Outside your scenario where you're using a CDN, there are situations where jQuery's default functionality is desirable: For example, when you want to simulate POST functionality across to another domain, without violating Same-Origin policy, jsonp with this cache busting feature can get that done for you.
If the server you're talking to expects something other than "callback" in the querystring for specifying the name of the callback function in the response, you can use the jsonp
config property - for example jsonp: 'myname'
would get you:
http://blah.com/blah.json?myname=JsonWrapping
I just found out this is somehow possible. I solved it like so:
$(document).ready(function(){
$.getJSON("http://example.com/staticjsonfile.json",function(data){
//callback function isn't here
}
});
function JsonWrapping(data){
//It's really here
alert(data);
}
This is not ideal, as you loose binding with the event that fired the Ajax request. So some hacking is required. However, it kinda gets the job done. I'd be very open to a better solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With