JSONP with Anonymous Callback Function
In my previous post [1], a complete JSONP example on both client side (browser) and server side (Google App Engine Python) is shown. The example in previous post needs a named, JavaScript callback function to handle the response returned from server. In this post, instead of using named callback function, an alternative choice is shown: use an anonymous callback function in JSONP request.
The main difference between named callback function and anonymous callback function is that in named callback function, only the name of callback function is supplied in the HTTP request, while in anonymous callback function, the whole callback function is supplied in the HTTP request.
The following is a complete example of JSONP with anonymous callback function.
index.html (run on client side, i.e., browser):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <!doctype html> <html> <head> <meta charset="utf-8"> <title>JSONP with Anonymous Callback Function on GAE Python example</title> </head> <body> <br style="line-height: 3em;" /> <form style="text-align: center;" action="javascript:jsonp();"> <input id="input1" type="text" value=""><br /> <input id="input2" type="text" value=""><br /> <input type="submit" value="Submit"> </form> <br style="line-height: 3em;" /> <div id="info" style="text-align: center;"> try to input something and then submit. a JSONP request will be sent to Google App Engine Python server and then response will be sent back. </div> <script src="jsonp.js"></script> </body> </html> |
jsonp.js (run on client side, i.e., browser):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /* send data to GAE Python server */ function jsonp() { var input1value = document.getElementById('input1').value; var input2value = document.getElementById('input2').value; // anonymous callback function to process JSON data returned from server. var callback = function(JSONdata) { /* In order to parse data, we have to know the structure of data from server in advance */ /* show data returned from server */ var infoElem = document.getElementById('info'); infoElem.innerHTML = 'input1: ' + JSONdata[0]['input1'] + '<br />'; infoElem.innerHTML += 'input2: ' + JSONdata[1]['input2'] + '<br />'; infoElem.innerHTML += JSONdata[2] + '<br />'; infoElem.innerHTML += JSONdata[3] + '<br />'; }; var url = '/jsonp?callback=' + encodeURIComponent(callback.toString()) + '&input1=' + encodeURIComponent(input1value) + '&input2=' + encodeURIComponent(input2value); var ext = document.createElement('script'); ext.setAttribute('src', url); document.getElementsByTagName("head")[0].appendChild(ext); } |
Note
In '/jsonp?callback=' + encodeURIComponent(callback.toString())
, the
whole anonymous callback function is supplied in the HTTP request.
jsonp.py (run on server side, i.e., GAE Python):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #!/usr/bin/env python # -*- coding:utf-8 -*- import webapp2 import urllib2 import json class JSONPPage(webapp2.RequestHandler): def get(self): input1 = urllib2.unquote(self.request.get('input1')) input2 = urllib2.unquote(self.request.get('input2')) result = [{ 'input1': input1 }, { 'input2': input2 }, ('message #1', 'from', 'server'), ('message #2', 'from', 'server')] self.response.headers['Content-Type'] = 'application/javascript' self.response.out.write( "(%s)(%s);" % (urllib2.unquote(self.request.get('callback')), json.dumps(result)) ) application = webapp2.WSGIApplication([ ('/jsonp', JSONPPage), ], debug=True) |
Note
In the code:
self.response.out.write(
"(%s)(%s);" %
(urllib2.unquote(self.request.get('callback')),
json.dumps(result))
)
The anonymous callback function is put inside parentheses. Without the parentheses, error will occur while executing the function on client. Compared with example in previous post [1], the named callback function does not need to be inside parentheses. This is another difference between named and anonymous callback function.
Also do not forget the semicolon in (%s)(%s);
app.yaml (on server side, GAE Python config file):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | application: jsonp-anonymous-callback-function-gae-python version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: / static_files: index.html upload: index.html - url: /jsonp.js static_files: jsonp.js upload: jsonp.js - url: /jsonp script: jsonp.application |
Caveat
The anonymous function is passed as argument in the URL. If the anonymous function is too long, this may exceed the length limit of URI, i.e., the server will return HTTP 414 error (Requested URI too long). As a result, if a callback function is so long such that it exceeds URI length limit, the only choice is to use named callback function.
If you want to use JSONP with object instance function as callback function, see [2].
Tested on: Ubuntu Linux 14.10, Google App Engine Python SDK 1.9.18
References:
[1] | (1, 2) JSONP on Google App Engine Python |
[2] | Use Object Instance Function as JSONP Callback Function |