SSE (Server-Sent Events)
部分內容由 LLM 生成,尚未經過人工驗證。
HTTP 長連線,伺服器單向推送事件至客戶端。基於 text/event-stream MIME type,瀏覽器內建重連機制。
連線流程
sequenceDiagram
participant C as Client
participant S as Server
C->>S: GET /events<br/>Accept: text/event-stream
S-->>C: 200 OK<br/>Content-Type: text/event-stream
Note over S,C: 連線保持開啟
loop 持續推送
S-->>C: data: {...}\n\n
end
C->>S: 連線中斷
C->>S: GET /events(自動重連)
Event 格式
id: 1
event: update
data: {"key":"value"}
retry: 3000| 欄位 | 說明 |
|---|---|
id | 事件 ID,重連時透過 Last-Event-ID header 傳送 |
event | 事件類型(預設 message) |
data | 資料內容,多行則每行一個 data: |
retry | 重連間隔(毫秒) |
實作
Server (Go Echo)
main.go
e.GET("/events", func(c echo.Context) error {
w := c.Response()
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
w.WriteHeader(http.StatusOK)
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case t := <-ticker.C:
fmt.Fprintf(w, "data: %s\n\n", t.Format(time.RFC3339))
w.Flush()
case <-c.Request().Context().Done():
return nil
}
}
})Client (TypeScript)
sse.ts
const es = new EventSource("/events")
es.onmessage = (e: MessageEvent) => {
console.log(e.data)
}
es.addEventListener("update", (e: MessageEvent) => {
console.log("update:", e.data)
})
es.onerror = () => es.close()比較
| SSE | WebSocket | Long Polling | |
|---|---|---|---|
| 方向 | Server → Client | 雙向 | Server → Client |
| 協定 | HTTP | WS (TCP upgrade) | HTTP |
| 重連 | 內建自動 | 需手動 | 需手動 |
| 複雜度 | 低 | 中 | 中 |
| 適用場景 | 通知、Feed、Log | 聊天、遊戲 | 舊系統相容 |