loading...

Understanding Server-Sent Events

praneetnadkar profile image Praneet Nadkar ・3 min read

Since a last few weeks I have been checking this with a lot of dev(s) that I know, if they are aware of server-sent events. Surprisingly a very few of them know what is a server-sent event. Let us understand this term.

What is SSE?

As the name suggests, an event that is sent or initiated by a server, and this is exactly what it does.
According to the wiki page, Server-Sent Events (SSE) is a server push technology enabling a client to receive automatic updates from a server via HTTP connection.
This is standardized as the part of HTML5. The server-sent event is an API that is operated through the EventSource interface

A client subscribes to a “stream” from a server and the server will send messages (“event-stream”) to the client until the server closes the stream.
It is the server that decides when and what to send the client and when to end the stream.

Why should you know about SSE?

Since the applications and their users are becoming more real-time oriented, you need Server-Sent Events. Displaying the last data updates to your users may change their actions.

Why SSE? I have Websockets.

WebSockets indeed is a long awaited evolution in client/server web technology. They allow a
single TCP socket connection to be established between the client and server which allows for bi-directional, full duplex, messages to be instantly distributed. Now there is a catch, if you read this meticulously, you would definitely notice that WebSockets are bi-directional. So if I need only unidirectional, WebSockets will cause great latency issues.

SSE is single directional (server to client) which surely would improve the latency issues. If we are looking from a server load point of view, SSE can be a way much better option than WebSockets.

Fields

As per the MDN, an event stream is a simple stream of text data which must be encoded using UTF-8. Messages in the event stream are separated by a pair of newline characters. A colon as the first character of a line is in essence a comment, and is ignored.

Each message received has some combination of the following fields, one per line:

event

A string identifying the type of event described. If this is specified, an event will be dispatched on the browser to the listener for the specified event name; the website source code should use addEventListener() to listen for named events. The onmessage handler is called if no event name is specified for a message.

data

The data field for the message. When the EventSource receives multiple consecutive lines that begin with data:, it will concatenate them, inserting a newline character between each one. Trailing newlines are removed.

id

The event ID to set the EventSource object's last event ID value.

retry

The reconnection time to use when attempting to send the event. This must be an integer, specifying the reconnection time in milliseconds. If a non-integer value is specified, the field is ignored.

click here for MDN Docs

Examples

To use the server-sent events, we need to call an API from a client and then the server will keep on sending the events, till the stream is closed.

.Net Core

Create a controller with any route. Add the following code to the controller.

        [HttpGet]
        public async Task Get()
        {
            var response = Response;
            response.Headers.Add("Content-Type", "text/event-stream");

            for (var i = 0; true; ++i)
            {
                await response.WriteAsync($"data: Controller {i} at {DateTime.Now}\r\r");

                response.Body.Flush();
                await Task.Delay(5 * 1000);
            }
        }

In this implementation we are using the WriteAsync method in from the Microsoft.AspNetCore.Http namespace. The writeAsync method will write the given text to the response body with the UTF-8 encoding.

HTML

<html>

<body>
    <script type="text/javascript">
        if (!!window.EventSource) {
            var source = new EventSource('https://localhost:44317/api/sse');
            source.addEventListener('message', function (e) {
                console.log(e.data);
            }, false)

            source.addEventListener('open', function (e) {
                console.log(e);
            }, false)

            source.addEventListener('error', function (e) {
                if (e.eventPhase == EventSource.CLOSED)
                    source.close()
                if (e.target.readyState == EventSource.CLOSED) {
                    console.log("Disconnected");
                }
                else if (e.target.readyState == EventSource.CONNECTING) {
                    console.log("Connecting...");
                }
            }, false)
        } else {
            console.log("Your browser doesn't support SSE")
        }
    </script>
</body>

</html>

When I ran the HTML, this is how the output was showing up in the console.
sse

Posted on by:

praneetnadkar profile

Praneet Nadkar

@praneetnadkar

Developer. Foodie. Working on .Net tech stack, GraphQL, Azure and AWS.

Discussion

markdown guide