Many web apps nowadays, including project I’m working on, rely on real time notifications from the server. GMail instantaneously adds incoming mail, Facebook shows chat messages and likes, list can go on.
My app does the same: it subscribes to certain topics and keeps open channel for server updates. Traditionally, we’ve been using long polling for that, but it felt like a hack, so we decided to switch to web sockets and fall back to long polling for legacy browsers. It took me 2 years to get to Ilya Grigorik’s «High Performance Browser Networking» book and realise that Server-Sent Events was much better choice. Here’s why.
Firstly, SSE is designed for tasks like mine: subscribe to continuous events/messages stream. Look, what it does out of the box:
- Auto-recover if connection was dropped
- Track last event id and continue from that one after connection reestablished
- Custom events
Our WebSocket based solution still doesn’t allow receiving events happened during ‘radio silence’. Reestablishing connection is not as easy as it sounds: dropped connection has to be detected first and reconnect attempts shouldn’t happen too often are just first 2 things from the top of my head to keep in mind. Finally, without introducing sub-protocol, WebSocket has only one kind of text message — the message.
Secondly, due to underlying protocol, it’s much easier to implement SSE on the server and fall back to alternative transport on the client.
- SSE is purely HTTP(s) based.
- Message format is extremely simple
Having HTTP(s) transport means that when EventSource is not available, we can easily fallback to XmlHTTPRequest. This is exactly what Google’s first suggested polyfill does. As a side note, having HTTP(s) also means you stuck with text messages only (or Base64 encoded binaries).
Then, look at this raw HTTP SSE messages and tell me you have no idea what they mean:
OK, there were few hints, but you got the point. I used to implement WebSocket’s HyBi 13 protocol and let me tell you that wasn’t experience normal people would enjoy. Simplest SSE implementation, on the other hand, took me about an hour of node.js witchcraft.
On the client side everything looks just as simple. End point is called EventSource. Add event listener method is called, surprise, addEventListener:
1 2 3 4 5 6 |
var messenger = new EventSource("/stream"); ["open", "message", "close", "error", "myEvent"].forEach(function (eventName) { messenger.addEventListener(eventName, function (e) { console.log(eventName, (e.data || e.readyState || e)); }, false); }); |
As of version 42, Google Chrome DevTools have adequate support for SSE messages and I expect same is true for much older versions. WebSocket support was there for years.
Talking about browsers, all Internet Explorers including Edge DO NOT support SSE. They do, however, support WebSockets since IE10. This is unfortunate and something to take into account.
So, if your task is subscribing to events stream and having IE polyfilled until they finally move to WebKit (if we wish it all together, this finally might happen) doesn’t scare you, Server-Sent Events is nice alternative to WebSocket. I wish I knew about them at the moment we made that architectural decision.
Sample SSE application can be found here.