Server-Sent Events (SSE) is technology that used for implementing real-time communication where the server send proactive data to the client.
Traditionally, clients creates an HTTP connection to the server to receive data. To receive regular updates, Polling or Long Polling techniques are often used via recurring HTTP requests.
As an alternative to a persistent connection, we can use Websockets which enable continuous two-way communication without establishing a new connection. Websocket is the best way if the application needs send and receive data intensively between client and server. However, in most cases, such as live dashboard or live analytics board, we only need to receive data from the server. In this scenario, Websockets would be an unnecessary burden.
To address this, we can use Server-Sent Events (SSE). Official details about this protocol can be found in the Server-sent events standard documentation.

Compared to Polling or Websockets, SSE offers the following benefits for one way scenario:
Although lightweight and efficient, SSE has several limitations:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
$eventData = [
'message' => 'Hello from PHP!',
'time' => time()
];
// Data wajib diawali dengan "data: " dan diakhiri "\n\n"
echo "data: " . json_encode($eventData) . "\n\n";
ob_flush();
flush();
sleep(5); // Simulasi penundaan 5 detik
$eventData = [
'message' => 'Another message from PHP!',
'time' => time()
];
echo "data: " . json_encode($eventData) . "\n\n";
ob_flush();
flush();
package main
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
func main() {
http.HandleFunc("/sse", 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")
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Streaming unsupported!", http.StatusInternalServerError)
return
}
eventData := map[string]interface{}{
"message": "Hello from Golang!",
"time": time.Now().Unix(),
}
// Parse ke JSON dan kirim dengan format SSE
jsonData, _ := json.Marshal(eventData)
fmt.Fprintf(w, "data: %s\n\n", jsonData)
flusher.Flush()
time.Sleep(5 * time.Second) // Simulasi penundaan 5 detik
eventData = map[string]interface{}{
"message": "Another message from Golang!",
"time": time.Now().Unix(),
}
jsonData, _ = json.Marshal(eventData)
fmt.Fprintf(w, "data: %s\n\n", jsonData)
flusher.Flush()
})
fmt.Println("Starting server on port 8080")
http.ListenAndServe(":8080", nil)
}
Note: