andersch.dev

<2025-03-26 Wed>
[ web ]

Server-Sent Events (SSE)

Server-Sent Events (SSE) allows a web server to push real-time updates to a client (i.e. a web browser) over a single, long-lived HTTP connection. Unlike bidirectional WebSockets, SSE is unidirectional, meaning communication only flows from the server to the client.

This makes SSE suitable for news feeds, stock tickers, and any other application where the server needs to constantly push information to the client without the overhead of two-way communication.

Example using Go (Golang)

package main

import "fmt"; import "log"; import "net/http"; import "time";

func sseHandler(w http.ResponseWriter, r *http.Request) {
    // sse headers
    w.Header().Set("Content-Type",  "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection",    "keep-alive")

    // ticker to send events every second
    ticker := time.NewTicker(1 * time.Second)
    defer ticker.Stop()

    done := r.Context().Done() // channel to signal when client disconnects

    for {
        select {
        case <-ticker.C: // clock
            // send current time as an event
            currentTime := time.Now().Format(time.RFC3339)
            fmt.Fprintf(w, "data: %s\n\n", currentTime)

            // flush response writer to send data immediately
            if f, ok := w.(http.Flusher); ok {
                f.Flush()
            } else {
                log.Println("Streaming unsupported!")
                return
            }

        case <-done:
            log.Println("Client disconnected")
            return
        }
    }
}

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        http.ServeFile(w, r, "index.html")
    })

    http.HandleFunc("/events", sseHandler)
    log.Println("SSE server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
<!DOCTYPE html>
<html>
<head>
    <title>SSE Example</title>
</head>
<body>
    <h1>SSE Example</h1>
    <div id="output"></div>

    <script>
        const outputDiv = document.getElementById('output');

        const eventSource = new EventSource('/events'); // establish SSE connection

        eventSource.onmessage = (event) => {
            outputDiv.innerHTML += `<p>Received: ${event.data}</p>`;
        };

        eventSource.onerror = (error) => {
            console.error("SSE error:", error);
            eventSource.close(); // Close the connection on error
        };

        eventSource.onopen = () => { console.log("SSE connection opened"); }
    </script>
</body>
</html>