Instantly share code, notes, and snippets.

@jareware /README.md
Last active Apr 23, 2018

Embed
What would you like to do?
Server-Sent Events Demo

Server-Sent Events Demo

Server-Sent events is a specification for implementing server-side-push for web frontend applications, through plain-old HTTP.

It is best contrasted with WebSockets, which offer a full-duplex messaging channel over a custom protocol, operating within a single TCP connection (with an HTTP-compatible handshake).

Trying out the demo

  1. Clone this gist
  2. node server.js
  3. Navigate to http://localhost:8888/
  4. See the events start rolling in
  5. Navigate away from the page, and back again
    • the node console will report the client going away and coming back
    • the client will automatically reconnect to the event source
  6. While on the page, kill the node process, then restart it
    • the client will report loss of connection
    • the client will automatically reconnect when the server comes back
    • the client will inform the server of the last message it saw (see below)

Main disadvantages

  • Support is not universal
    • Neither is WebSocket's, though
    • The single major difference is in IE-land; not even 11 supports SSE
  • There is no return channel for the client to use

Main advantages

  • As WebSocket is a custom protocol, it needs explicit support
    • Which is far from being a given in more exotic network setups
    • Proxies/middleware are good examples of where WebSockets often break
  • Easy to test and write automation against, since it's just HTTP
  • Things like session management work exactly like the rest of your HTTP API
  • Some have reported better latency performance over WebSockets
    • Though I'm not entirely sure how that's possible; maybe browsers' HTTP stacks are more mature than the WebSocket counterparts?
    • Maybe some extra latency comes from the initial protocol switch?
  • Sometimes you simply don't need a full-duplex connection
    • Talk to server over standard REST JSON, for example
    • Deliver notifications over SSE
  • Browser handles reconnections automatically behind the scenes
    • If you tag your messages with ID's, the browser will provide the last ID it saw along with the reconnection, allowing you to send the correct amount of catch-up to the client
    • Your frontend-application won't even have to care about the ID; it's by the server, for the server
  • While both WebSockets and SSE will likely need a polyfill/fallback in the wild, note that:
    • To allow falling back from WebSockets, you need a separate, completely different API on the backend for that
    • Falling back from SSE can be handled entirely client-side
  • Forward-compatible with... whatever may come!
    • SSE is an abstraction over push-events, with management of the underlying connection offloaded to the browser
    • There's no reason HTTP needs to be the only available transport: mobile user-agents could use the push-notification service of their platform, for instance
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, height=device-height" />
<title>Server-Sent Events Demo</title>
<style type="text/css">
body {
font-family: 'Open Sans', sans-serif;
}
</style>
</head>
<body>
<h1>Server-Sent Events Demo</h1>
<ul></ul>
<script>
(function() { "use strict";
var ul = document.querySelector('ul');
var es = new EventSource('/events');
function li(text) {
var li = document.createElement('li');
li.innerText = text;
ul.appendChild(li);
}
es.addEventListener('open', function() {
li('Server connected :)');
});
es.addEventListener('my-custom-event', function(event) {
li(event.data);
});
es.addEventListener('error', function() {
li('Server unavailable :(');
});
})();
</script>
</body>
</html>
var fs = require('fs');
var http = require('http');
var connectionCounter = 1;
http.createServer(function(request, response) {
if (request.url === '/') {
response.writeHead(200, { 'Content-Type': 'text/html' });
response.write(fs.readFileSync('index.html'));
response.end();
} else if (request.url === '/events') {
var thisConnection = connectionCounter++;
var thisEvent = 1;
console.log('Client connected to event stream (connection #' + thisConnection + ', Last-Event-Id: ' + request.headers['last-event-id'] + ')');
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache' // let intermediaries know to NOT cache anything
});
var ticker = setInterval(function() {
response.write('event: my-custom-event\n');
response.write('id: ' + (thisConnection * 1000 + thisEvent) + '\n');
response.write('data: Server says hi! (event #' + thisEvent++ +' of connection #' + thisConnection + ')\n\n');
}, 2500);
request.on('close', function() {
console.log('Client disconnected from event stream (connection #' + thisConnection + ')');
response.end();
clearInterval(ticker);
});
} else {
response.writeHead(404);
response.end();
}
}).listen(8888);
@titan83

This comment has been minimized.

Show comment
Hide comment
@titan83

titan83 Apr 23, 2018

@jareware, thanks for your example.
But I found very unpleasant problem and I still can't solve it(
Problem in browsers (Chrome at least): they send "heartbeat" messages to SSE server with some interval (Chrome - around 2 mins), and on server side I can't diffirenciate "heartbeat" and "new client" messages, so my server increase amount of input connections continously.
May be you know how to solve this issue?
Thanks.

titan83 commented Apr 23, 2018

@jareware, thanks for your example.
But I found very unpleasant problem and I still can't solve it(
Problem in browsers (Chrome at least): they send "heartbeat" messages to SSE server with some interval (Chrome - around 2 mins), and on server side I can't diffirenciate "heartbeat" and "new client" messages, so my server increase amount of input connections continously.
May be you know how to solve this issue?
Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment