Using Script tags to do remote HTTP calls in Javascript

I’ve been racking my brains all afternoon trying to find a workable solution to the problem of not being able to make remote HTTP calls using javascript. This is an issue for me because so much of my work takes place inside a TiddlyWiki which, when viewed locally (from a file:// url) is a perfect environment for bypassing standard AJAX security and creating mashups. The problem comes when I want to put a TiddlyWiki online to show off what I’ve done or to let other people use it – the local behaviour is not replicated and my mashups go kaput.

There are several ways of getting around this security restriction, known as Javascript’s same-origin policy, but they generally involve using iframes and other files on your own server. I wanted to keep everything in one self-contained file, so I pretty much ruled these out. The idea of using a local proxy was thrown out for the same reasons.

A found a some info that covered “dynamic Script tags”, which requires the remote server to serve you a tailored javascript file that called a function you supplied the name of, with the data you wanted returned as a parameter to that function, but that was really just a facade on top of another proxy story.

Then I hit upon this wonderful website, which gave an insight into an API architecture being adapted by, amongst others, Yahoo!. The idea revolves around the API itself returning JSON encapsulated in a function call, so the body of the response is essentially the parameter to the function. You add a Script tag to your page with the API call as the src attribute and when the browser loads the script, it ends up calling the function, which you write support for in your code.

// adapted from http://www.hunlock.com/blogs/Howto_Dynamically_Insert_Javascript_And_CSS
var headID = document.getElementsByTagName("head")[0];         
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.onload=scriptLoaded;
newScript.src = 'http://api.flickr.com/services/feeds/photos_public.gne?tags=sunset&format=json';
headID.appendChild(newScript);

jsonFlickrFeed = function(feed) {
   // deal with the feed!
};

// when the script is finished, remove the script node we added
// removeNode is a custom function defined in the TiddlyWiki source code: http://svn.tiddlywiki.org/Trunk/core/js/Dom.js
// It ensures that the eventhandler is removed before deletion
scriptLoaded = function() {
	removeNode(newScript);
};

It’s simple, elegant and easy to work with. There are two alternative implementations that I’ve seen today: the first and simplest for the server to support, is exemplified by Flickr – the function call wrapped around the response data is fixed and you have to know what it is to write support for it [edit – they do support the next method too]; Yahoo! Pipes (and more generally, Yahoo!’s other developer API’s) supports the second method – the API takes the name of a callback function as a parameter and then wraps the data in a call to this function, which takes away the dependency on knowing the specific function to write support for.

This isn’t the perfect solution, as it leaves you wide open to exploitation from cross-site scripting, so I don’t recommend using this with API’s that you don’t trust. I feel pretty safe using Yahoo!’s API’s, but someone less salubrious could inject whatever they wanted in there. You don’t really want that when the script has access to the global object and, therefore, everything on your page.

This takes me one step closer to making it easier to replicate your offline TiddlyWiki environment online… Hurrah…

About these ads

10 Comments

  1. Posted September 17, 2007 at 6:49 pm | Permalink

    The only problem I encountered with dynamic insertion of script tags was a lack of support in Safari. At least that was v2, I don’t know if they’ve fixed/changed that in the v3 betas. I suppose I ought to investigate/try it out.

    The JSON sent back in a call back function is nifty – a guy wrote a version of my flickr dom badge using that.

  2. Posted September 18, 2007 at 9:37 am | Permalink

    Hey, that’s cool. I’m really interested in how you did the funky 3D view of your code in the title bar.

  3. Posted September 18, 2007 at 10:45 am | Permalink

    The 3D view is a simple “screw around with a text block in Fireworks with the skew tool”. I can throw up the source png somewhere if you want to have a look at it.

  4. Posted September 18, 2007 at 12:10 pm | Permalink

    Jon, suggest checking out the JSONP convention as well. One of the issues with JSON is that a JSON response alone is useless – the third party’s Javascript has to do something with it at the end, like call a callback method.

  5. Posted September 18, 2007 at 5:33 pm | Permalink

    Cheers Patrick, that’d be interesting. I’m no Fireworks expert, so I thought you’d done some wicked image manipulation programmatically… although technically I guess you did.

  6. Posted September 18, 2007 at 5:37 pm | Permalink

    Michael, ok, that’s pretty interesting… what does JSONP let you do that wouldn’t be enabled by the JSON returning a custom callback function?

  7. i wasn't at your persc%nto presentation
    Posted September 21, 2007 at 10:33 am | Permalink

    can i flag up a major tech post of the month here?

    surely there must be someway of deploying directly from your local server on a lightweight system like jetty. of course I have little experience with JS and have just blasted through it first time… at least my first point is valid!

  8. Posted September 24, 2007 at 1:36 pm | Permalink

    Thanks! Ok, so I’m not with you yet – Jetty’s a Java-based web server, right? What are you referring to when you say “deploying directly from your local server”? The problem I’m trying to solve here is the restriction on javascript running in a browser…

  9. Luis
    Posted November 13, 2007 at 9:59 am | Permalink

    Hey, As the first guy said, current KHTML browsers lack of execution in the script tag, and depends on your page statistics this is requirement (5%).

    So, doesn’t this finally mean that I have to setup a proxy and make a simple XHR call?

  10. Posted June 2, 2009 at 12:02 pm | Permalink

    I just read your post on Appjet closing. There is an app I wrote on appjet that does JavaScript remoting for any webpage.

    http://json-proxy.appjet.net/

    For example, if you want to get google.com:

    So callback() would receive google.com’s html as a string.

    Too bad it won’t be up for long.


2 Trackbacks/Pingbacks

  1. Google gadgets

    So I’ve been messing around with various different widget frameworks on and off over the last few months as preparation for a workshop I’m going to be involved with. I started out with Yahoo Widgets (née Konfabulator) mainly because the ex…

  2. […] reasons. JSONP is a convention between the client and the server to bypass this restriction using script tag injection. More explanation here. It is this convention that allows us to call Yahoo Pipes directly from […]

Follow

Get every new post delivered to your Inbox.