SSE, which stands for Server-Sent Events, is a quite nice way of simplex data transfer from server to clients, at server’s will. This avoids repetitive polling by the clients or unnecessary full-duplex web sockets. Typical SSE use cases include, news updates, social media feeds, stock price changes, etc.
In this discussion we will see how we can implement a simple SSE using just NodeJS. I feel like I can express it better without a library.
We will implement a simple News service. Which will eventually run out of news, and we will notify the client about it. Let’s see the project structure.
The project is available on github. Here I will be explaining the core concepts only. That resides in handlers/index.js. I have a function named sseHandler, which basically takes care of the incoming SSE requests, as the name suggests.
SSE works on top of HTTP, but whether it is HTTP1.1 or HTTP2, that depends on the server configuration. I am using HTTP1.1, as the limitations that come with HTTP1.1 is not bothering me at the moment. That being said, we need to enforce a ground rule, SSE connection can not end. This is not your typical request-response, rather it is, connection-responses thing.
But, how do we send back data without ending the response, right? That would be done using two things. First of all, look at the response header “Content-Type”: “text/event-stream”. This header says that the content of the body will be stream(continuous data) of texts. Secondly, keep writing data to response body using a method which does not flush the response body, in our case, res.write.
Now it is time to talk about the most important part of the process. The data format. In each SSE message there are 4 parts. event, data, id, retry. Except for data all are optional. There should be a colon(:) after the name of each event. For example, data: hello, client!
We specify the event name in event field. We pass event id using id field. Data is sent using the data field. If the connection drops then the client tries to reconnect, this re-connection time(in milliseconds) can be set through retry field.
Each field should be separated from each other using a new line character. Each individual message should end by using two consecutive new line characters.
Let’s see all of them in action.
data: First message\nevent: sampleEvent\nid: 1\nretry:1000\n\ndata:Second message\nevent:sampleEvent\nid:2\n\n
If we translate that into code, then it will look like this.
Okay, so we are clear on how to make it happen in our server, now let’s talk about the counterpart, our browsers, and not IE.
This time we will pull the
EventSource API from the bag of web APIs offered by the browser.
This is pretty straightforward. You instantiate an object of EventSource. You will be having callbacks like onopen, onmessage, onerror. For this demonstration, I am not sending custom event, so my data will end up in onmessage.
In order to listen to custom events, you need to do the following.
And that is it.
These events can be seen in network tab of a browser.
I have stated earlier that there is some limitation if we use SSE over HTTP1.1. We can not have more than 6 open connections to a singe domain from a single browser, although we can connect to multiple domains from the same browser. Using HTTP2 we can overcome this issue, the default value of maximum open connections is 100. This is well documented in MDN. Link is provided below.
SSE is pretty solid way for uni-direction communication. It is also easy to implement.
My project is available here https://github.com/iamparnab/SSE.node.js. MDN https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events.