We live in a world where real-time data streaming has become paramount. Real-time data streaming has become a necessity in modern applications because it keeps users notified immediately an event happens. But most of the communication we see on the internet involves a client application making a request to the server which in turn processes the request and send back response to the client. This takes time to process and there are scenarios where a server needs to send data to the client without the client necessarily initiating a request.
This could be done using long polling, websockets, webhooks or server-sent events. Examples of real-time applications include; instant messaging, notification system, online gaming, chat apps, videoconferencing, data streaming, sport updates, stock prices e.t.c. But our main focus in the article is Server-sent events.
You can also read
Stream Processing Paradigm: Enabling Continuous Data Analysis and Transformation
Video Tutorial
If you prefer to watch and learn an in-depth tutorial on how to implement server-sent events(SSEs) with react js and node js, here is a full video for you.
Please don't forget to like, comment, subscribe to my youtube channel and share the video with your friends.
Different techniques for client-server communication
Below are some of the techniques used for client server communication
Polling is a technique where the application repeatedly polls data from the server and if you are familiar HTTP protocol, it involves request/response format. It is a traditional technique used by the vast majority of AJAX applications. The trade off with polling is that it creates greater HTTP overhead.
Long polling is a technique in which if the server does not have the data available when a request is made from the client, the server holds the request open until data is available. The server responds when data becomes available, closes the connection and when the client receives the new data, it sends another request to the server again. This cycle is repeated endlessly until either of them closes the connection. The major drawback of this mechanism is once the server has sent the data; it cannot send further data until a new poll request arrives.
WebSockets is a communication protocol that provides full-duplex bi-directional, communication channel over a single TCP connection. This mechanism creates a two-way connection between the server and the client i.e the server can send data to the client and client can send data to the server as well This is great for things like chat apps, instant messaging e.t.c.
However, sometimes you need some updates from the server without waiting for the client to repeatedly initiate requests. This includes; friends' online status updates, newsfeeds e.t.c
Server-Sent Events is an HTTP standard that enables a client application to automatically receive updates or event streams from the server once an initial connection has been established. It’s a server push technology that allows client apps to receive data transmission from the server via an HTTP connection and describes how servers can stream data to the client once an initial connection has been established. Server-sent events (SSEs) are unidirectional in nature i.e., only the server can push updates to client. SSE is commonly used to send automatic updates or continuous data streams to a browser client.
The main difference between Server-Sent Events and long-polling is that SSEs are handled directly by the browser and the client app simply has to listen for messages.
SSE contained in the JavaScript EventSource API in order to open a connection to the server to continue receiving event streams. In server-sent events, automatic updates are sent to client rather than pulled from the client.
You can also read
Stream Processing Paradigm: Enabling Continuous Data Analysis and Transformation
Server-sent events VS Websockets
WebSockets provide bi-directional, full-duplex communication. It creates a two-way channel where the client can send data to the server and the server can also send data to client. This enables a real-time communication in both directions. This makes it effective for cases like real-time chat apps, games etc.
However, there are some scenarios where client apps don’t need to send data to server but only consumes from the server and this is where server-sent events(SSEs) comes in.
In SSEs, the communication is unidirectional i.e., the server continuously pushed event streams to the client once an initial connection has been established. Examples include; real-time notification systems, sport updates, stock prices, status updates, newsfeed, cryptocurrency updates e.t.c
Server-sent Events implementation
Server sent server can be implemented both server side and client-side environment.
Client-side API
The SSE client API is contained in the EventSource object.
When using SSE, the browser will generate an instance of EventSource first to initiate a connection to the server.
In order to detect if a browser supports SSEs, use the code snippet below;
const url = "http://localhost:5000/stream"
//url can be your server url
if ('EventSource' in window) {
let source = new EventSource(url)
}
Note: The URL above can be in the same domain as the current URL of the application or it can be cross domain as well. When the URL passed to the EventSource constructor is an absolute URL, its origin (scheme, domain, port) must match that of the server.
When a cross-domain is passed as the url, you can specify a second _options _ parameter with withCredentials property to indicate whether to send the cookie & auth headers altogether or not as shown below.
const url = "http://localhost:5000/stream"
//url is your server url
if ('EventSource' in window) {
let source = new EventSource(url, {withCredentials: true})
}
Eventsource object events
By default, there are three (3) events which include message, open and error to listen on.
The open event indicates a successful connection between the server and the client.
The error event handles an error connection between the server and the client.
The message event is used to listen on live stream data emitted by the server after a successful connection.
SSEs are flexible enough that you can even define your own custom events on the server which you in turn listen on, on the client side.
Below are the three (3) default event listeners with their callbacks.
source.addEventListener('message', function(e) {
console.log(e.data);
}, false);
source.addEventListener('open', function(e) {
// successful connection.
}, false);
source.addEventListener('error', function(e) {
// error occurred
}, false);
EventSource object properties
Some of the properties of the EventSource instance include;
-
readyState e.g source.readyState
- readyState value of 0 indicates connecting
- readyState value of 1 indicates open
- readyState value of 0 indicates closed
url e.g source.url returns connection url
withCredentials e.g source.withCredentials show whether or not withCredentials is true.
EventSource object methods
The closed() method can be called to close the connection e.g source.closed()
Server-side implementation
SSE Data format
The SSE data sent by the server to the browser must be UTF-8 encoded text with the following HTTP header.
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
The information sent each time consists of several messages, and each message is separated by \n\n. Each message is composed of several lines of code internally, and each line should be written as follows.
The above field can take the following four values.
*data * indicates the payload to be sent.
retry indicates the reconnection time in seconds and it's optional
event can be a custom event e.g notification defaults to message when no event is passed
id indicates the id of the data to be sent and it's optional
const emitSSE= (res, id, data) =>{
res.write('id: ' + id + '\n');
res.write("data: " + data + '\n\n');
res.flush()
}
const handleSSE = (req, res) =>{
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
const id = (new Date()).toLocaleTimeString();
// Sends a SSE every 3 seconds on a single connection.
setInterval(function() {
emitSSE(res, id, (new Date()).toLocaleTimeString());
}, 3000);
emitSSE(res, id, (new Date()).toLocaleTimeString());
}
//use it
app.get("/stream", handleSSE)
Using Server-sent events with React.js and Node.js
Implementing server-sent events can be fairly simple but it gets confusing when you want target or send an event to a specific user as there is no clear way to exchange user data with the server.
But in the video tutorial below; we have addressed the issues of sending global events as well as targeting specific users.
In the video tutorial below, we are going to build and deploy a realtime twitter-like newsfeed using server-sent events(SSE) with react.js, node.js and mongodb from the scratch and deploy it on cpanel.
This tutorial is for beginners and advanced programmers who wish to learn to implement the following;
- How to implement SSE in react js and node js application
- How to broadcast data to all users using server-sent events
- How to send data to a specific or single user using server-sent events
- How to implement LIKE button
- API(Application Programming Interface)
- React Hooks(useState, useContext, useReducer)
- Hosting(Deployment) on cpanel
Resources & Demo
You can also read
Stream Processing Paradigm: Enabling Continuous Data Analysis and Transformation
Summary
Realtime data streaming has become a necessity in a standard modern application as this keeps your user notified of all the activities within your application. In this article, we discussed various techniques of client server communication and the need to go with server-sent events. Server-sent events(SSE) is a server push technology that enables a client to receive live stream updates from the server via a HTTP connection. It is lightweight and supported by most modern browsers and as a result, it's well suited for real-time automatic data stream from the server
Video Tutorial
If you want to watch and learn an in-depth tutorial on how to implement server-sent events(SSEs) with react js and node js, here is a video for you.
Please don't forget to like, comment, subscribe to my youtube channel and share the video with your friends.
Top comments (20)
Great article!
A couple of questions regarding SSEs...
Have you come across issues with the maximum number of connections (using http/1) as noted here? Or do you ensure http/2 is used?
Have you come across any limitations on the server for keeping connections open? I haven't been able to find much information on how many connections a server can keep open. I realize that's based on server hardware, number of instances, number of concurrent users, etc... but I've been trying to find a baseline number to compare.
Thank you very much for asking this question. The max number(6) of connections indicated over there is per browser per domain. For instance with Google Chrome you can open 6 max number of connections to example.com and with ms edge you can still open another max connection of 6 to the same domain.
To answer your question;
If you find anything worth sharing, please don't forget to share it with us. Thank you
Hello,
The number of connections that the server support also depends on what web server you are using, for example, if you are using Apache, this formula gives you the number according to the hardware of your server:
(Total Memory – Critical Services Memory) / Size Per Apache process
It gives you the limit recommended for the Apache configuration, so your server will be optimized.
Thank you! 😊
👍
Great post with clear and easy explanation 👌
My pleasure
keep up man. great content
My pleasure
awesome article. I Just yesterday coded somehing very similar by chance, since my boss need to display streamed data in "real-time-charts".
Wow that's great. Which tech stacks did u use?
Great article
Thank you, Jeremiah
Thanks!
Welcome
The Reveal Music was here ,thanks for this tutorial man keep up the good work
You are welcome. Glad you found it helpful
I think npmjs.com/package/@microsoft/fetch... deserves a mention here as well :-)