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()

比較

SSEWebSocketLong Polling
方向Server → Client雙向Server → Client
協定HTTPWS (TCP upgrade)HTTP
重連內建自動需手動需手動
複雜度
適用場景通知、Feed、Log聊天、遊戲舊系統相容

相關主題