SSE Server Sent Events
Server Sent Events SSE are a well established web standard.
They allow a web server to push messages to the client.
I have created a minimal example https://github.com/janhalfar/sse-playground/tree/main/minimal to illustrate the technology.
Minimal Example in action
if you clone https://github.com/janhalfar/sse-playground locally and run go run minimal/main.go

Minimal server
This server will:
- serve its minimal frontend on http://localhost:8080
- serve a time event 100 times on http://localhost/sse/time
Let´s take a look at the server response with:
curl -v localhost:8080/sse/time
% curl -v localhost:8080/sse/time
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /sse/time HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/event-stream
< Date: Fri, 16 Sep 2022 14:49:17 GMT
< Transfer-Encoding: chunked
<
event: time
id: 1
data: 2022-09-16T16:49:17.482796+02:00
event: time
id: 2
data: 2022-09-16T16:49:17.498366+02:00
event: time
id: 3
data: 2022-09-16T16:49:17.514079+02:00
event: time
id: 4
data: 2022-09-16T16:49:17.529639+02:00
event: time
id: 5
data: 2022-09-16T16:49:17.545335+02:00
...
serving the frontend
The first thing the server is to serve a frontend, which is described below:
http.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(index)
}))
serving time events
http.HandleFunc("/sse/time", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
flusher, _ := w.(http.Flusher)
i := 0
for i < 100 {
i++
eventID := fmt.Sprint(i)
_, err := w.Write([]byte(
"event: time\n" +
"id: " + eventID + "\n" +
"data: " + time.Now().Format(time.RFC3339Nano) + "\n\n",
))
if err != nil {
fmt.Println("connection pbly closed", i, err)
return
}
flusher.Flush()
time.Sleep(time.Millisecond * 15)
fmt.Println("sent", i, "to", r.RemoteAddr)
}
}))
Minimal client
const updateTime = (t) => document.getElementById("serverTime").innerText = t;
//------------------------------------------------------------
// SSE server sent events
//------------------------------------------------------------
const sse = new EventSource("/sse/time");
sse.addEventListener("open", (event) => {
console.log("connected", event);
});
sse.addEventListener("time", (event) => {
updateTime(event.data);
});
sse.addEventListener("error", (event) => {
if (event.eventPhase == EventSource.CLOSED) {
console.log("closed, but an error ?!", sse.readyState);
} else {
console.error("an error occured", event.type, event.error);
}
});