Cross-domain AJAX using Flash

TiwyFeeds, a recent AJAX project of mine, uses a Flash object for storing data on the client and also to make cross-domain requests to the Bloglines API. As I explained in that post, the Flash API that it uses set some pretty heavy constraints: only XML could be sent and received.

After Jason Levitt started experimenting with this component, he quickly ran against its limitations. Mainly, he needed to exchange arbitrarily formatted text, such as a POST sending form encoded parameters in the body and receiving JSON encoded data.

So I researched the issue a bit more and found a newsgroup post (in french) on hacking Flash to allow raw text in the HTTP request and response body.

This hack works and is now integrated in the Flash4AJAX object, part of my Tiwy* projects. I intend to provide a nice javascript wrapper some time later, to mimic the regular XMLHttp API.
For now, the Flash object provides a custom interface, that I used directly in a demo page using the cross-domain capability.

You can look at the source of the page for the detailled APIs exposed by the Flash object, the main ones being "fs.XmlHttp(urlString, callbackNameString, verbString, bodyString, contentTypeString)" to start the request and "GetVariable('retText')" to get the content from the response.
Note that this API is not re-entrant at this time: you can only make a single remote call at a given time. I'll probably fix this soon, when I write a nice javascript wrapper.


sendAndLoad hack details:

The technique, explained by Zwetan, steals the sendAndLoad method off of the LoadVars or the XML prototype and sticks it on a custom object. There are a couple of supporting methods and fields that need to be added for the implanted method to function properly (contentType, toString()).
I made my own small contribution to the approach by also implanting the addRequestHeader function.

There are still some shortcomings, compared to the XMLHttp API. First, the HTTP status code from the response is only available in IE.
Second, there is no way to access the response headers.
Third, you can only do GET and POST, but no PUT, DELETE or other methods.
The last restriction not to forget is that Flash will only allow requests to domains that explicitly allow it, by publishing a policy file (crossdomain.xml), for security reasons. A number of sites already have one, such as Yahoo/Flickr, Amazon or Bloglines.
Let me know if you find more.

Overall, this solution offers an interesting new trade-off. You gain quite a bit of flexibility and scalability compared to the traditional techniques (API proxying or remoting via <script> tag), but it also has some restrictions and depends on Flash version 8.
I'm considering to re-write the object to support Flash 6 or 7 players, but luckily, Flash 8 his having a fast adoption.


Some pointers on learning ActionScript/Flash:

Dare asked me to post some pointers on how I learnt ActionScript and Flash.
I must say that I still don't know very much and I am especially ignorant when it comes to Flash IDEs, animations and movies.
From my understanding, a SWF file is composed of two parts, the media (timeline, movies, etc.) and the code.
The mtasc compiler (free and open) can take a bunch of ActionScript source files (.as) and generate an SWF file or overwrite the code section of an existing SWF. ActionScript is similar to javascript, as it is another variant of ECMAScript.
The mtasc tutorial provides steps to compiling a simple class.
The macromedia documentation provides an ActionScript language reference as well as a reference documentation and a dictionary for the libraries.

I also used a doc from OSFlash, which lists the Flash 8 functions available thru mtasc, to learn about ExternalInterface (the new Flash/javascript interop API in Flash 8).


Related links:


Update (2006/03/14): I wrote a simple javascript wrapper, FlashXMLHttpRequest, which emulates XMLHttpRequest. The cross-domain demo page is updated to make use of it.
The code snippet shows pretty much all of what's supported:

var xhr = new FlashXMLHttpRequest();
xhr.onload = function() { alert(xhr.responseText); }
xhr.open(method, url);
xhr.setRequestHeader("Content-Type", contentType);
xhr.send(body);

Update (2006/04/07): I made a small update to the Flash4AJAX library, allowing to make the Flash object less obstrusive in the display of the page while retaining the cross-domain capability.
No more un-necessary visible Flash object.
Well, actually, the object is trully invisible in Firefox, but there is still 1 pixel left in IE. You can see the change in the demo page.

Posted by Julien on March 03, 2006. Permalink
Comments

nice post.

fyi, one minor correction:

--
The last restriction not to forget is that Flash will only allow requests to domains that explicitly allow it,
--

Flash only allows requests to third party domains that explicitly allow it. Same domain requests are allowed.

Also, you can download a free compiler for Flash / ActionScript 3, and the IDE for it (based on Eclipse) from:

http://labs.macromedia.com

(Sounds like this would be a better match for you).

Also, check out the URLLoader API in AS3:

http://livedocs.macromedia.com/labs/1/flex/langref/index.html

It will give you more control over what you are trying to do.

mike chambers

mesh@adobe.com

Posted by: mike chambers at March 6, 2006 12:56 PM

Julien, good work. You made the impossible work! Nice.

Posted by: Brad Neuberg at March 7, 2006 12:13 PM

I tested the demo in my local server
but It does not work in my server.
I'm very newbee for the flash
But I can find the document describing the Flash8 security change.
Is it make the reason?
I run the apache web server and accessed via http protocol.
also store the crossdomain.xml in the target server with "...allow-access-from domain="*"..." tag.
Flash4AJAX is the best solution for overcome the cross-domain restriction ever I searched.

Posted by: Mountie Lee at April 24, 2006 07:55 AM

Julien,

Do you think that it is possible to make the Flash communication a little more discreet (no status bar flickers)?

I am using the IMG tag now instead of the SCRIPT tag to do cross-domain scripting. The reason being that the status bar doesn't flicker whenever I do an IMG poll to remote server in IE, but still does in FireFox, whereas the SCRIPT tag flickers in both IE and Firefox.

Now the reason I was so interested in Flash cross-site scripting is that it has the potential to do cross-domain silent polls, or so I thought. But from your demo page, it seems like the Flash method is still not as discreet as I hoped, in other words the status bar still flickers.

Posted by: Roy at April 30, 2006 02:52 PM

Roy,
I hadn't looked at that so far, but I'll certainly keep an eye on this issue in my future Flash experiments.
I'm open to tips and advice from any Flash guru reading this, please email me.

Posted by: Julien Couvreur at May 1, 2006 09:08 AM

Because embedding Flash into web scripts proved to slower page loading, Flash is moving toward non-web applications, or so I think.

Posted by: Mag at May 15, 2006 03:37 AM

For some reason the responseText and FlashHelper.getFlash().GetVariable("retText") returne Undefined. Why is that? This is only within my code. Im using it within my class method and have it calling back my class method.

Is there a way to get this library to handle multiple requests at once? Im going to have multiple windows request from it.

Posted by: Abe at May 23, 2006 01:58 PM

Abe,
You should check that the server actually returned some content and not some error (404, 500, ...). If the server returns an error, then probably retText would be undefined.

Could you clarify what you mean by "multiple windows"?

Posted by: Julien Couvreur at May 23, 2006 04:34 PM

Hi. By multiple window i mean multiple window.open(). Im getting JS to open up a window to show googlemaps in each window. I first need to perform a geocode of the provided addresses which the rpc call will handle for me. Since there are multi windows open each making a request to the flah object and so re-entrants, Im pretty much screwed. From what I can see in the procided .JS file this multiple calling will simply cancel the previous request?!

Do you provide the .fla source file? I dont know action script right now but Im desperate enough to learn to add what i need.

Posted by: Abe at May 23, 2006 05:31 PM

BTW my javascript code makes multiple requests to Yahoo's geociding service and also to another XML webservice for other data. It eventually display Google Maps either within the same browser window or within individual popup browser windows. The way things are set up, the user can click a link to have multiple window popup at once and so multiple requests to the same flash object at once.

Im new to Javascript so feel free to provide a solution

Posted by: Abe at May 23, 2006 05:40 PM

I seem to be getting the javascript error message: "Object doesn't support this property or method" from this line in the Flash4AjaxHelper.js file:

fs.XmlHttp(_url, CallbackManager.registerCallback(callback), _method, body, _contentType, _headers);

Any ideas?
_url="http://api.local.yahoo.com/MapsService/V1/geocode?appid=YahooDemo&location=12+euclid+ave"
_method="GET"
body=""
_contentType = null
_headers = ? (i didnt provide any and debugger isnt revealing anything to me)

Posted by: Abe at May 23, 2006 07:58 PM

For some reason the responseText and FlashHelper.getFlash().GetVariable("retText") returne Undefined. Why is that? This is only within my code. Im using it within my class method and have it calling back my class method.

Posted by: latino at June 1, 2006 08:24 AM
Trackbacks
Comments are closed. You can contact me by email.