Go - WebSockets & SSE
Beginner 10/10
Teacher 10/10
Architect 10/10
WebSockets & Server-Sent Events (SSE)
Use WebSockets for bidirectional real-time messaging and SSE for unidirectional server-to-client streams.
Try it: Implement SSE that sends a timestamp every second.
SSE with net/http
package main
import (
"fmt"
"net/http"
"time"
)
func sse(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")
fl, _ := w.(http.Flusher)
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for i:=0; i<5; i++ { // demo
<-ticker.C
fmt.Fprintf(w, "data: %s\n\n", time.Now().Format(time.RFC3339))
if fl != nil { fl.Flush() }
}
}
func main(){
http.HandleFunc("/events", sse)
http.ListenAndServe(":8080", nil)
}
WebSocket (concept)
You can implement WebSockets using a library (e.g., gorilla/websocket) or manually via net/http
hijacking. Libraries handle frames and close semantics.
// Pseudocode with gorilla/websocket
// var upgrader = websocket.Upgrader{}
// func ws(w http.ResponseWriter, r *http.Request){
// c, _ := upgrader.Upgrade(w, r, nil)
// defer c.Close()
// for {
// _, msg, err := c.ReadMessage(); if err != nil { break }
// c.WriteMessage(websocket.TextMessage, append([]byte("echo: "), msg...))
// }
// }
Common errors
- Forgetting to flush SSE responses.
- Not handling client disconnects (browser closed) and breaking out of loops.
- Missing CORS/CSRF considerations on WebSocket endpoints.
Practice
- Add a
retry
field in SSE and test reconnect behavior in the browser. - Implement a ping/pong heartbeat for WebSockets.
Quick quiz
- When would you choose SSE over WebSockets?