Server Sent Events

an intro

What is it?

A communication protocol that works on top of HTTP

and also a JavaScript API

( standardised as part of HTML5 )

that provides a way to push notifications from server to client

without the client's involvement

Typical client-server

Server sent events

Use cases

Be aware

  • The SSE protocol is not bidirectional, i.e. it only allows sending data from server to client. It turns out that this is enough to pull off all previous examples.
  • The payload of Server Sent Events is UTF-8 encoded text data. Again, this is probably just what you need.

Alternatives

The usual suspects:

  • Websockets
  • Polling

Okay, how does this work?


// Subscribe for events on event source of given URL
var eventSource = new EventSource("http://some.service.com/event-source/");
            

// Subscribe for events on event source of given URL
var eventSource = new EventSource("http://some.service.com/event-source/");

// And then listen for events of specific type
eventSource.addEventListener("progress", function (event) {
  var eventData = JSON.parse(event.data);
  window.alert('Progress is currently at ' + eventData.currentProgress + '%');
});
            

// Subscribe for events on event source of given URL
var eventSource = new EventSource("http://some.service.com/event-source/");

// And then listen for events of specific type
eventSource.addEventListener("progress", function (event) {
  var eventData = JSON.parse(event.data);
  window.alert('Progress is currently at ' + eventData.currentProgress + '%');
});

// When you're done
eventSource.close();
            

// Listen for errors
eventSource.addEventListener('error', function (event) {
  if (event.readyState === EventSource.CLOSED) {
    console.log('Connection was closed');
    return;
  }
  console.log('OMG unexpected error occurred. Here\'s some info: ', event);
});
            

// Listen for notifications that the SSE connection has been established
eventSource.addEventListener('open', function (event) {
  console.log('Connection was opened, here come the tasty events');
});
            

HOW (SERVER SIDE)


// In this Node.js example, we receive an HTTP request
// (e.g. on http://some.service.com/event-source/)
// so we're given a response object 'res' to write onto

// 1) We write necessary-ish HTTP headers onto the response
res.writeHead(200, {
  'Content-Type': 'text/event-stream',
  'Cache-Control': 'no-cache',
  'Connection': 'keep-alive'
});

// 2) Then we write an event (= simply text) onto the response
res.write('event:progress\n');
res.write('data:' + JSON.stringify({ currentProgress: 15 }) + '\n\n');
            

// To send a second progress event, we simply repeat
res.write('event:progress\n');
res.write('data:' + JSON.stringify({ percentage: 20 }) + '\n\n');
            

// To send a ping event every second

var id = 0;

setInterval(function () {

  ++id;

  res.write('id:' + id + '\n');
  res.write('event:ping\n');
  res.write('data:Still here bro\n\n');

}, 1000);
            
(Setting an ID lets the browser keep track of the last event fired so that, if the connection to the server is dropped, a special HTTP header (Last-Event-ID) is set with the new request. The browser will attempt to reconnect roughly 3 seconds after each connection is closed.)

How does that differ from a vanilla HTTP server?


// We never
res.end();
            

Here's a PHP implementation, if you're interested.

Don't websockets already do all that?

Yes, but they're more complex than you need.*

Websockets allow bi-directional communication, at a price:

  • There's much more to figure out in terms of the application level protocol.
  • Getting a server up and running is significantly more complicated.
  • You miss out on the magical automatic reconnection & event ids.
* Unless you actually do need full-duplex or binary streams
Also, you can polyfill SSE all the way back to IE8

Can't I use (long) polling instead?

Yes, but it's so much worse than the real thing.

  • Drains resources by sending requests, on a timer, for the entire lifetime of the app.
  • Annoyingly floods network logs with a gazillion entries nobody cares for.
  • It's so 2010.*

*Actually the very first Comet implementations date back to 2000

Remember, Chrome is your friend

Read / do more

The End :)