以下是一个完整的 Server-Sent Events (SSE) 在 Go 中的实现示例,包含服务端和客户端的代码。SSE 适用于服务器向客户端单向推送实时数据的场景(如通知、日志流等)。
Server-Sent Events (SSE)
HTTP/2 + SSE
SSE Golang实现
1. 服务端代码(Go)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package main
import (
"fmt"
"log"
"net/http"
"time"
)
// SSE 事件流处理函数
func sseHandler(w http.ResponseWriter, r *http.Request) {
// 设置响应头,表明是 SSE 流
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
// 创建一个通道用于模拟数据更新
eventChan := make(chan string)
defer close(eventChan)
// 模拟异步数据生成(实际可能是数据库监听、MQ 订阅等)
go func() {
for i := 1; i <= 10; i++ {
eventChan <- fmt.Sprintf("Event %d: %s", i, time.Now().Format("15:04:05"))
time.Sleep(2 * time.Second) // 每 2 秒推送一次
}
}()
// 监听客户端断开连接
ctx := r.Context()
for {
select {
case <-ctx.Done():
log.Println("Client disconnected")
return
case event := <-eventChan:
// 写入 SSE 格式的数据(data: 开头,结尾用 \n\n)
_, err := fmt.Fprintf(w, "data: %s\n\n", event)
if err != nil {
log.Println("Write error:", err)
return
}
// 刷新缓冲区,确保数据立即发送
w.(http.Flusher).Flush()
}
}
}
func main() {
http.HandleFunc("/sse", sseHandler)
http.Handle("/", http.FileServer(http.Dir("./static"))) // 静态文件服务(放客户端 HTML)
log.Println("Server started at :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
|
2. 客户端代码(HTML + JavaScript)
在项目目录下创建 static/index.html
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<!DOCTYPE html>
<html>
<head>
<title>SSE Demo</title>
</head>
<body>
<h1>SSE 实时数据流</h1>
<div id="events"></div>
<script>
const eventSource = new EventSource("/sse");
// 监听服务器推送的事件
eventSource.onmessage = (e) => {
document.getElementById("events").innerHTML += `<p>${e.data}</p>`;
};
// 监听错误(如连接断开)
eventSource.onerror = (e) => {
console.error("SSE Error:", e);
eventSource.close();
};
</script>
</body>
</html>
|
3. 运行步骤
- 创建项目目录结构:
1
2
3
4
|
your_project/
├── main.go
└── static/
└── index.html
|
- 启动服务端:
- 打开浏览器访问
http://localhost:8080
,页面将每 2 秒显示一条服务器推送的事件。
关键点说明
- SSE 协议格式:
每条消息以 data:
开头,结尾用两个换行符 \n\n
(参考 MDN 规范)。
- 服务端要求:
- 必须设置
Content-Type: text/event-stream
。
- 使用
Flush()
立即发送数据。
- 客户端 API:
浏览器原生支持 EventSource
,自动处理重连。
- 断开连接:
服务端通过 r.Context().Done()
检测客户端是否断开。
扩展功能
- 自定义事件类型:
服务端发送:
1
|
fmt.Fprintf(w, "event: customEvent\ndata: %s\n\n", "Custom Data")
|
客户端监听:
1
2
3
|
eventSource.addEventListener("customEvent", (e) => {
console.log("Custom Event:", e.data);
});
|
- 重试机制:
服务端可发送 retry: 5000\n
指定客户端重连间隔(毫秒)。
如果需要处理更复杂的场景(如鉴权),可以在 URL 中添加 token 或使用 Cookie。