Jul03
Cross-site HTTP Request for jsonip
I've added cross-site HTTP request support for jsonip, a micro-service I introduced previously that retrieves a client's IP address. Now, with HTTP access controls and a browser that supports them (such as Firefox 3.5,) any site can use a regular XmlHTTPRequest to utilize the service instead of JSONP. This might not be terribly useful today, as most browsers don't support HTTP access controls, but the arrival of Firefox 3.5 beacons the future of possibilities.
Here's a new cross-site HTTP request usage example:
<script>
var req = new XMLHttpRequest();
req.open('GET', 'http://jsonip.appspot.com', true);
req.onreadystatechange = function (e) {
if (req.readyState === 4) {
if(req.status === 200) {
var ip = JSON.parse(req.responseText);
alert(ip.address);
} else {
alert("Error loading page\n");
}
}
};
req.send(null);
</script>
You'll notice it looks just like a regular XmlHTTPRequest, except the domain does not have to be your own. My service at jsonip.appspot.com is using special headers that allow this to work instead of greeting you with the usual permission errors.
The source code of the python script I use for the service is below. You'll notice where the special headers are added:
import os
import cgi
form = cgi.FieldStorage()
callback = form.getvalue('callback','')
address = cgi.escape(os.environ["REMOTE_ADDR"])
json = '{"ip": "'+address+'", "address":"'+address+'"}'
#Allow cross domain XHR
print 'Access-Control-Allow-Origin: *'
print 'Access-Control-Allow-Methods: GET'
if callback != '':
print 'Content-Type: application/javascript'
result = callback+'('+json+');'
else:
print 'Content-Type: application/json'
result = json
print ''
print result
The magic happens here, with these printed headers:
print 'Access-Control-Allow-Origin: *'
print 'Access-Control-Allow-Methods: GET'
The first header means any domain can use this service cross-domain. Alternatively, you could have a comma seperated list of domains instead of a * to allow requests only from those domains. I want my service open to all sites, so I use a *.
The second header is self-explanatory (as if the first wasn't:) there's no need to support any other HTTP methods for this simple service, so I limit them to GET.
There are more access control headers available, so do make sure to read the article before trying these out. Some configurations could be dangerous, depending on your service.
Other jsonip Changes
- JSON output uses double quotes for property names, as per the JSON specification
- Added
addressproperty to use instead of the oldipproperty to retrieve the IP address. I've left theipproperty for backwards compatibility.
The old, JSONP method of use still works as expected:
<script>
// callback function
function getip(jsonip){
alert(jsonip.address) // alerts the ip address
}
</script>
<script type="text/javascript" src="http://jsonip.appspot.com/?callback=getip"> </script>