Server Sent Events (SSE) with Go

Server Sent Events (SSE) with Go

During my last vacation, I started learning about real-time communication. In my exploration process, I found Server-Sent-Events (SSE). In this article, I’ll explore how to implement SSE in Go, discussing benefits and use cases.

What is a Server Sent Event?

SSE is a web technology that allows real-time, unidirectional communication from server to client using a persistent HTTP connection. It means that servers only send updates to clients, and clients don't have the ability to send updates to servers.

WebScockets vs Server-Send-Events

Both WebSockets and Server-Sent Events (SSE) are designed to facilitate real-time communication between a server and a client. However, they differ significantly in their approach and functionality. WebSockets establish a full-duplex communication channel over a single, long-lived connection, which means both the client and the server can send messages to each other at any time. This bidirectional capability makes WebSockets particularly suitable for applications that require frequent and dynamic data exchange, such as online gaming, chat applications, or collaborative editing tools.

On the other hand, SSE is a simpler protocol that creates a unidirectional channel from the server to the client. This means that while the server can continuously push updates to the client, the client cannot send messages back to the server over the same connection. SSE is ideal for applications where the server needs to send continuous updates to the client, like live news feeds, stock price updates, or real-time notifications. SSE uses a persistent HTTP connection, which is inherently more firewall-friendly and easier to implement than WebSockets, especially when dealing with simple one-way data streams.

The code snippets below show how to implement SSE with Go and how to use that code on the client side using JavaScript.

package main

import (
  "fmt"
  "net/http"
  "time"
)

func main() {
  http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")
    w.Header().Set("Access-Control-Allow-Origin", "*")

    for {
      // Simulate sending events every second
      fmt.Fprintf(w, "data: %s\n\n", time.Now().Format(time.Stamp))
      w.(http.Flusher).Flush()
      time.Sleep(1 * time.Second)
    }
  })

  http.ListenAndServe(":8080", nil)
}
w.Header().Set("Content-Type", "text/event-stream")

Set the content type to "text/event-stream," which informs the client that this is an SSE connection.

w.Header().Set("Cache-Control", "no-cache")

Preventing the caching of the event stream.

w.Header().Set("Connection", "keep-alive")

Keep the connection open for continuous streaming.

w.Header().Set("Access-Control-Allow-Origin", "*")

Allows CORS requests from any domain.

for {
      fmt.Fprintf(w, "data: %s\n\n", time.Now().Format(time.Stamp))
      w.(http.Flusher).Flush()
      time.Sleep(1 * time.Second)
    }

In this infinite loop, data is generated every second. The Flusher interface immediately sends the generated data to the client using Flush().

Now let's see how to use event streaming on the client side.

<script>
  const eventSource = new EventSource('http://localhost:8080/events')

  eventSource.onmessage = function (event) {
    console.log('Message received: ', event.data)
  }

  eventSource.onerror = function (event) {
    console.error('An error occurred:', event)
  }
</script>

The EventSource interface creates a persistent connection to an HTTP server that sends data in the "text/event-stream" format.

Use cases:

  • Real-time dashboards

  • Live Scoring apps

  • Social media feeds

  • Stock market tickers

  • Progress indicators in long-running tasks

Advantages

Simplicity: SSE is easy to implement on both the server and client sides and uses an event-based interface.

Compatibility: SSE is supported by all modern browsers.

Efficiency: Unlike WebSockets, SSE uses a standard HTTP connection, avoiding extra overhead.

Disadvantages

Unidirectional Communication: SSE only allows communication in one direction, limiting scenarios that require bidirectional interaction between server and client.

Error Handling: Advanced error handling and connection recovery need to be implemented manually.

Conclusion:

Server Sent Events provide an effective and efficient way to implement real-time data communication on the web. Their simplicity, compatibility, and efficiency make them an excellent choice for many applications. However, their unidirectional nature and error handling challenges may lead you to choose WebSockets or alternatives.