So I had implemented a simple JSON data server with Werkzeug for a classroom
experiment. Unfortunately in my haste to get everything up and running I
totally forgot about the fact that, since we cannot allow uploads to this
server of various custom made webpages, using jQuery's $.ajax() everything just fails since it
will then be a cross-site scripting request.
So, normally you would do something like the following in order to return JSON
data:
Which would be used with the $.ajax() call in a way like the following:
$.ajax({
type: "POST",
url: "http://example.com/json/something",
data: "parameter=value",
dataType: "json",
error: function(XMLHttpRequest, textStatus, errorThrown){},
success: function(data, msg){}
});
Which is perfectly fine for scripts getting and using the data on the same
host/domain. But, as said before, this will fail with warnings similar to:
"Access to restricted URI denied" code: "1012" nsresult: "0xdeadc0de
(NS_ERROR_DOM_BAD_URI)".
One way out of this is using JSONP. jQuery has a $.getJSON()
function, which loads JSON data
using a HTTP GET request. Now, the simplistic way to convert your code would
be to change it as such:
$.getJSON("http://example.com/json/something",
function(data){}
);
But this causes another issue. Since $.getJSON() GETs the JSON data, but
doesn't use eval() on it, but instead pulls the result into script tags,
it somehow causes,on Firefox at least, an invalid label error. In order to fix
this you need to set up the JSON data server to properly support a callback
argument, to use $.getJSON() how it is meant to be used:
$.getJSON("http://example.com/json/something?jsoncallback=?",
function(data){}
);
In the code above the additional parameter jsoncallback will, thanks to
jQuery, get the question mark replaced by an alphanumeric string (typically in
the form of jsonp followed by a timestamp). This value should be used to
wrap the resulting JSON data with. This means you would have to change the
initial Python code to something like this:
return request.args.get('jsoncallback') + '(' + json.dumps(data) + ')'
Of course this causes problems when you want to reuse the code for both AJAX
use on the same host/domain and use it from outside. So in order to make both
work you can test on whether or not the callback parameter is available and
return the appropriate data. I came up with this little snippet for that:
def jsonwrapper(self, request, data):
callback = request.args.get('jsoncallback')
if callback:
return callback + '(' + json.dumps(data) + ')'
else:
return json.dumps(data)