Server-Sent Events (SSE)

While WebSockets provide a powerful solution for bidirectional, full-duplex communication between clients and servers, not all applications require this level of interactivity.  In scenarios where real-time updates from the server to the client are sufficient, a simpler and often more efficient alternative exists: Server-Sent Events (SSE).

A Simple One-Way Data Flow

SSE excels in situations where the client doesn’t need to send data back to the server, or where this communication can happen asynchronously using traditional request-response mechanisms.

Consider These Scenarios:

  • A live news feed where the server pushes updates to clients as new articles are published.
  • A stock ticker displaying real-time price changes.
  • A notification system where the server alerts users of new messages or events.

In these cases, the client primarily acts as a receiver, passively consuming updates from the server. SSE provides a streamlined approach for this one-way communication.

SSE Under the Hood: Riding the HTTP Stream

Unlike WebSockets, which require a protocol upgrade, SSE operates entirely over HTTP.  The server establishes a persistent HTTP connection and streams data to the client as a series of text-based events. Each event consists of:

  • Event Name (optional): Identifies the type of event.
  • Data:  The actual payload, usually in plain text or JSON format.

Here’s an example of what an SSE data stream might look like:

JSON
data: {"price": 123.45, "symbol": "AAPL"}

event: newMessage

data: {"user": "John", "message": "Hello!"}

data: {"temperature": 25, "humidity": 60}

Setting the Stage: Establishing an SSE Connection

To initiate an SSE connection, the client sends a regular HTTP request to a server endpoint that’s designed to handle SSE. The key difference lies in the Accept header, which the client sets to text/event-stream:

HTTP
GET /my-sse-endpoint HTTP/1.1

Accept: text/event-stream

Upon receiving this request, the server keeps the connection open and sets the Content-Type header to text/event-stream. This signals to the client that it will be receiving a stream of events, not a single response.

Client-Side Handling: Listening for Events

On the client side, JavaScript provides the EventSource API to handle SSE connections:

JavaScript
const eventSource = new EventSource('/my-sse-endpoint');

eventSource.onmessage = (event) => {

  const data = JSON.parse(event.data);

  // Process the received data

};

eventSource.onerror = (error) => {

  // Handle connection errors

};

The EventSource object establishes the connection and provides event listeners to handle incoming data and errors.

SSE in Action: A Streamlined Flow

  1. The client sends an HTTP request with the Accept: text/event-stream header.
  2. The server accepts the request, keeps the connection open, and sets the Content-Type header to text/event-stream.
  3. The server sends events as they occur, formatted as text with optional event names and data payloads.
  4. The client’s EventSource object receives these events and triggers the corresponding event listeners (e.g., onmessage).
  5. The connection remains open until explicitly closed by either party.
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: SSE Connection Establishment and Event Flow

    Client->>+Server: HTTP GET Request<br/>Accept: text/event-stream
    Server-->>-Client: HTTP 200 OK<br/>Content-Type: text/event-stream
    
    Note over Client,Server: Connection Remains Open

    rect rgb(230, 255, 230)
        Server->>Client: Event 1 (data payload)
        Note right of Client: EventSource triggers<br/>onmessage listener
        Server->>Client: Event 2 (named event + data)
        Note right of Client: EventSource triggers<br/>specific event listener
        Server->>Client: Event 3 (data payload)
        Note right of Client: EventSource triggers<br/>onmessage listener
    end

    Note over Client,Server: Connection Remains Open Until Explicitly Closed

    opt Connection Closure
        Client->>Server: Close Connection
        Server-->>Client: Connection Closed
    end

SSE Advantages: Simplicity and Efficiency

SSE offers several benefits, especially when compared to WebSockets:

  • Simplicity:  Leveraging the familiar HTTP protocol simplifies implementation, both on the client and server.
  • Efficiency:  SSE‘s one-way data flow minimizes overhead, making it highly efficient for scenarios where the server is the primary data source.
  • Built-in Reconnection: The EventSource API automatically attempts to reconnect if the connection is interrupted, enhancing resilience.

SSE Considerations: Navigating the Limitations

While well-suited for certain use cases, SSE has some limitations to consider:

  • One-Way Communication: SSE is inherently unidirectional. While clients can send messages to the server, this requires separate HTTP requests.
  • Limited Browser Support for Multiple Connections:  Some older browsers may struggle to maintain multiple SSE connections simultaneously.
  • Potential for Long-Lived Connections: While generally efficient, long-lived SSE connections can consume server resources if not managed carefully.