Platinum Partner
java,frameworks

Tricks and Tips With Comet Part 1: Making All Browsers Work Properly

Writing Comet applications is more and more easy, thanks to frameworks like LIft and Atmosphere. On the Client side, the difference between Safari, Opera, Firefox, IE and Chrome can make your application completely unresponsive or broken. Of course, there are some tricks to make it work.

First, if you are new to Comet, I recommend you take a look at this introduction. For this serie, I will use my new project called Atmosphere, which is a framework for writing portable Comet and REST applications. I always use Firefox for developping, and recently I've got surprise when I 've realized all Atmosphere's sample did work on WebKit (Chrome, Safari) and Opera.

First, to make Safari works properly with the Comet technique called http streaming or forever frame, make sure, on the server side, you set the content-type properly and disable the cache.

res.setContentType("text/html");
res.addHeader("Cache-Control", "private");
res.addHeader("Pragma", "no-cache");

That works well with GlassFish and Jetty...but not Tomcat. Why? Because both Jetty and GlassFish append the charset for you all the time, and Tomcat don't. Safari seems to not like it. So the proper code consist of:

       

res.setContentType("text/html;charset=ISO-8859-1");
res.addHeader("Cache-Control", "private");
res.addHeader("Pragma", "no-cache");

Note that Firefox will work without the above, same for IE. Now the above will make the Comet technique called Long-polling working, but http streaming will still be broken on Safari. Why? Because when you suspend the response, if you don't fill out Safari with some data (~2k), all events that will happen once the response has been suspended will be written by the server, but never read/displayed in Safari, Chrome, IE and Opera.  As an example, I always output the following junk before I suspend a response in Atmosphere:

private final static String JUNK = "<!-- Comet is a programming technique that enables web " +
"servers to send data to the client without having any need " +
"for the client to request it. -->\n";

......

for (int i =0; i< 10; i++){
res.getWriter().write(JUNK);
}
res.getWriter().flush();  

If you are using Atmosphere REST module using Scala, you also need to do something like:

var JUNK : String = "<!-- Comet is a programming technique that enables web " +
"servers to send data to the client without having any need " +
"for the client to request it. -->\n"

@Suspend
@GET
@Produces(Array("text/html;charset=ISO-8859-1"))
def suspend() = {
var s = new StringBuilder()
for (i <- 0 to 10){
s.append(JUNK)
}
s.toString()
}

Quite painful but until websocket are widely adopted (will they?), you will need a little bit of hacking. But once you know them, that should be easy. Client library like JQuery and Dojo's Cometd implementation already do that for you, but if are using pure javascript (or iframe for the http streaming support), make sure you recall that simple tip. You can download many Comet samples from here. They work on any Java WebServer.

If you have any questions, post them on users@atmosphere.dev.java.net, use Nabble or or tweet them.

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}