JS Bits with Bill
JS Bits with Bill

JS Bits with Bill

Stream updates natively with EventSource 📡

Stream updates natively with EventSource 📡

JS Bits with Bill's photo
JS Bits with Bill

Published on Aug 13, 2020

3 min read

The EventSource object is a native Web interface used with server-sent events. If you're not familiar, server-sent events are messages sent by a server to client at any time (and not necessarily as an immediate response to a request like the tradition client-server model).

The most typical use case for using EventSource is wherever you need to broadcast periodic events from your server, such as an online stock quote application or perhaps a social medial site where users can see real-time notifications. Using EventSource, you can open a persistent connection to your server and push events to your client without the need to constantly poll for updates.

To see how this works, first create a new EventSource in your client code. The first argument is the URL of the server serving the events. From there, you can add event listeners for the open and message events:

const evtSource = new EventSource('/connect');

// Listen for "open" event when connected
evtSource.addEventListener('open', () => {
  console.log('Persistent connection to server opened');
});

// Listen for "message" event when received from server
evtSource.addEventListener('message', e => {
  console.log('Data received: ', e.data);
});

Here's a NodeJS server example that listens for the initial request and simulates sending periodic events:

app.get('/connect', (req, res) => {

  // Set headers
  res.status(200).set({
    'Connection': 'keep-alive',
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache'
  });

  // Broadcast a message with a random # every 2 seconds
  setInterval(() => {
    const number = Math.floor((Math.random() * 100));
    res.write(`data: ${number} \n\n`);
  }, 2000);
});

Some caveats: First, the headers should be exactly as shown since the events are sent in text/event-stream format and the connection needs to be kept alive with no caching.

Secondly, when testing this, I had trouble receiving events on the client until I read that the event stream response format is very particular. The response text must begin with data: . The custom message should follow and the line must be terminated with 2 \n characters otherwise the message will not be sent. You can send bigger bits of data by simply using JSON.stringify() on an object.

When you wish to close the connection simply run evtSource.close().

There's a bunch more on EventSource you can read on the MDN article linked below but that's how it works in a nutshell. What's really cool is that it's available natively in all modern browsers and is a much lighter-weight alternative to using a websocket library when all you need to do is broadcast events (websocket are needed for full-duplex communications however).

Lastly, although EventSource has been around forever, I first read about it as a sneaky way hackers can open connections to a malicious server in a XSS attack. Even if Security Ops are monitoring requests by watching fetch events or XMLHttpRequest, EventSource may not always be noticed (perhaps because it's more obscure?). In any case, it's a pretty cool tool to use when the situation calls for it! 📡

Links

MDN Article on EventSource


Check out more #JSBits at my blog, jsbits-yo.com. Or follow me on Twitter!

 
Share this