Golang 实现 SSE 服务端

53 min read

SSE(Server-Sent Event)是一种服务器向客户端推送实时数据的方式,它可以通过 HTTP 建立单向通信通道,让服务器将实时数据推送到客户端,客户端可以通过监听该通道来获取实时数据。

在 Golang 中,实现 SSE 服务端可以使用 net/http 包提供的 ServerSentEvent 类型和相关函数。下面是一个简单的示例代码:

package main

import (
    "fmt"
    "net/http"
    "time"
)

// 定义 SSE 事件
type MessageEvent struct {
    Id   string
    Name string
    Data string
}

// 实现 SSE 事件的 String() 方法
func (e MessageEvent) String() string {
    return fmt.Sprintf("id:%s\n"+
        "event:%s\n"+
        "data:%s\n\n", e.Id, e.Name, e.Data)
}

func main() {
    // 定义 SSE 事件通道
    messageChan := make(chan MessageEvent)

    // HTTP 请求处理函数
    http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
        // 设置 response header
        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)

        // 循环监听 SSE 事件通道
        for {
            // 从通道中读取事件
            message := <-messageChan

            // 向客户端发送 SSE 事件
            fmt.Fprintf(w, "%s", &message)

            // 刷新 response buffer
            w.(http.Flusher).Flush()
        }
    })

    // 启动 HTTP 服务器
    go func() {
        err := http.ListenAndServe(":8080", nil)
        if err != nil {
            panic(err)
        }
    }()

    // 定时向 SSE 事件通道中写入数据
    for i := 0; i < 10; i++ {
        messageChan <- MessageEvent{
            Id:   fmt.Sprintf("%d", i),
            Name: "message",
            Data: fmt.Sprintf("Message %d from server", i),
        }
        time.Sleep(time.Second)
    }
}

首先,我们定义了一个 MessageEvent 类型,并实现了 String() 方法。该类型表示一个 SSE 事件,并将事件内容格式化为 SSE 数据格式。

接着,我们在主函数中创建了一个 messageChan 通道,表示 SSE 事件通道。然后,我们使用 http.HandleFunc() 函数定义了一个 HTTP 请求处理函数,该函数会将 response header 设置为 SSE 事件格式,并循环监听 SSE 事件通道,从中读取事件并向客户端发送。

最后,我们启动了一个 HTTP 服务器,并定时向 SSE 事件通道中写入数据。在上面的示例代码中,我们向 SSE 事件通道中写入了 10 条消息,并设置每条消息的 id、name 和 data 属性,然后等待一秒钟后再次发送。当客户端连接到服务器时,服务端会持续向客户端推送 SSE 事件,客户端可以通过监听事件通道获取实时数据。