Saturday, January 21, 2012

Comet in a socket: supporting the non-supporters

This is part 3 in WebSocket series. Read part 1 and part 2 here.

In the previous part of the series we have covered all the historical basis of WebSocket protocol and learned how to use it in order to implement a very basic webchat service. Unfortunately, the WebSockets protocol is still only a draft and a novelty, and as such it is not yet consistently supported across all the major browser platforms. Have no fear, though, as there are ways to easily add the necessary support to all the major browsers - though usually not with a pure JavaScript solution.

Before we cover it, though, lets see how bad the situation really is.

WebSockets support in major browsers

Internet Explorer10+
FirefoxYes (*)
OperaYes (**)
(*) The WebSocket object is namespaced. If you want to use it, the easiest way to do it is by putting the following snippet at the beginning of your script:
if (window.MozWebSocket) {
 window.WebSocket = window.MozWebSocket;
(**) WebSocket support is disabled by default in Opera and requires you to enable it manually in opera:config#UserPrefs|EnableWebSockets.

As you can see, the support is currently not that bad - all the major browsers aside from Internet Explorer (surprised? didn't think so) support it, but some need additional hoops to jump through. And what is as important - WebSockets can be used in mobile applications, too! In defense of IE one must note that, at least, WebSockets will be supported in version 10 of that browser - but it is still a long time before IE 10 gains widespread adoption (since it is not even out yet).

So, what can one do to be able to use WebSockets in the browsers that support them, yet still work in others as well? Well, there are a few available options.

Ask users of non-compliant browsers to switch to a compliant one

Not really a solution in many cases - if you are developing an Internet service, you don't really want to shut out all the MSIE users. On the other hand, if all you are developing is an internal application that will be used in a company that already uses Firefox or Chrome as their main browser, or if you are only developing for the mobile, this "solution" may be viable. Lucky you!

Use a pure JavaScript workaround

If you need to support all the major browsers and yet you don't want to require any kind of external browser plugin (like Flash or Java), your options are pretty limited. You could develop a hybrid solution that takes advantage of WebSockets when they are available and gracefully falls back to older, inferior solutions otherwise. Such "inferior solutions" include all the techniques described in the first part of this series: polling, long polling, Comet etc. The obvious disadvantage would be worse performance (both client- and server-side) for such legacy option, but hey, beggars can't be choosers. At least your application works universally!

Use a plugin

If your nonfunctional requirements do not include "pure JavaScript solution", your options are much better. The most obvious and, actually, easiest solution is to use Flash as a fallback when WebSockets are not available. Sure, Flash doesn't work on (most) mobile platforms, but as I have already mentioned before - mobile support for WebSockets in itself is much, much better. So, by using a Flash script, you will effectively cover all your bases at small cost.

A favorite solution of mine, that I recommend, is a small script available here. Not only is it very lightweight, it can get you going in only three lines of additional code!
First, make sure you download swfobject.js and web_socket.js files, as well as WebSocketMain.swf Flash application. Put all those files in your web project that is already using WebSockets. Then, inside your JavaScript add this one initialization line:

WEB_SOCKET_SWF_LOCATION = <path to WebSocketMain.swf>
After that, include swfobject.js and web_socket.js. That's it, you're done!

Some additional parameters you may find useful when using this script are:
  • WEB_SOCKET_FORCE_FLASH - when set to true, will force Flash usage even if your browser supports WebSockets. Good for testing.
  • WEB_SOCKET_LOGGER - if you assign an object to this variable, said object's log() and error() methods will be called when the script wants to log something. Otherwise, the script will try to use window.console (if it exists) or will not log at all.
  • WEB_SOCKET_DEBUG - when set to true, the script will log some additional debugging info. Useful for troubleshooting.
Also, make sure that you include any of these options (as well as WEB_SOCKET_SWF_LOCATION) before you include web_socket.js script, otherwise it will not work.

Okay, I lied. You may (and probably do) need to do one more thing related to how Flash handles connection security. Namely, you need to provide a Flash policy file served on port 843 of your server (read more about Flash policy here). In a production environment you would most probably need to configure your web server to handle it by itself; for development, you can just write a very simple policy server yourself. If you do not want to (or do not know how), there is a very simple Flash policy server written in Java which you can find linked in this Less Rain blog entry (direct link). You can simply run this server via a "java -jar policyserver.jar" command, or you can start it manually in your Java application by invoking "PolicyServer.main(args);" method.

There are, of course, disadvantages to using a Flash solution:

  • Your users need to have either a WebSockets-compliant browser, or a Flash plugin installed
  • You need a separate policy file, thus opening an additional port on your server
  • Flash plugin will not connect to localhost - when testing it, make sure you are connecting through your real IP number
  • Flash plugin will not work from behind a corporate firewall / proxy server
All in all, though, Flash is a completely viable workaround for lack of WebSockets support and can serve you well till the standard gains full adoption.

This concludes this three-part WebSockets tutorial. If you have found it useful, or if you have your own experience working with WebSockets, please drop a comment!

1 comment:

  1. ad a little more of this. Great post. Thanks for the heads-up. This blog was very info

    commercial garbage cans