Server-Sent Events (SSE) 是一种在客户端和服务器之间建立单向、持久连接的技术,允许服务器推送实时更新到浏览器。SSE 主要用于向浏览器推送事件(如实时通知、消息、更新等),与 WebSocket 不同,SSE 是单向的:数据从服务器流向客户端,而 WebSocket 允许双向通信。
在 Go 中实现 SSE 可以通过标准的 net/http 包来完成。下面是如何在 Go 中实现 SSE 的基本步骤。
1. SSE 的基本原理
SSE 使用 HTTP 协议,并通过特定的 Content-Type 响应头来指定消息流格式:
- Content-Type:
text/event-stream,告诉浏览器该响应是一个 SSE 流。 - 事件数据: 每条消息以特定的格式(包括
data字段)发送,支持自定义事件类型。
每条消息的格式通常如下:
data: <消息内容>\n\n你可以使用其他字段,比如:
event: 指定事件类型。id: 指定事件 ID。retry: 指定客户端重试的时间间隔。
2. 在 Go 中实现 SSE 服务器
示例:创建一个 SSE 服务器
设置 HTTP 服务器:Go 中可以使用
http包来处理 HTTP 请求。编写 SSE 处理函数:该函数将设置必要的 HTTP 头部并持续发送事件。
完整的 Go SSE 示例
go
package main
import (
"fmt"
"log"
"net/http"
"time"
)
// 启动一个 SSE 流
func sseHandler(w http.ResponseWriter, r *http.Request) {
// 设置 HTTP 头部,指定响应类型为 SSE
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
// 持续发送数据
for {
// 发送消息,每 1 秒发送一次
message := fmt.Sprintf("data: %s\n\n", time.Now().Format(time.RFC3339))
_, err := w.Write([]byte(message))
if err != nil {
log.Println("Error writing to client:", err)
break
}
// 刷新缓冲区
flusher, ok := w.(http.Flusher)
if ok {
flusher.Flush()
}
// 每 1 秒发送一次数据
time.Sleep(1 * time.Second)
}
}
func main() {
// 设置 SSE 路由
http.HandleFunc("/events", sseHandler)
// 启动 HTTP 服务器
log.Println("SSE server started on :8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("Error starting server:", err)
}
}关键点说明:
- 设置
Content-Type:设置Content-Type为text/event-stream,指示浏览器这是一个 SSE 流。 Cache-Control: no-cache:防止缓存,以确保事件流实时更新。Connection: keep-alive:保持 HTTP 连接活跃。http.Flusher:确保数据被及时推送到客户端,而不是缓存在服务器端。Flusher接口用于强制刷新 HTTP 响应流。- 每秒推送数据:使用
time.Sleep每秒推送一次当前的时间。
3. 客户端代码(HTML + JavaScript)
客户端代码需要通过 JavaScript 使用 EventSource API 来接收从服务器推送的事件。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Demo</title>
</head>
<body>
<h1>SSE Demo</h1>
<div id="messages"></div>
<script type="text/javascript">
// 创建一个 EventSource 实例,连接到 SSE 服务器
const eventSource = new EventSource('/events');
// 监听 `message` 事件
eventSource.onmessage = function(event) {
// 获取数据并显示
const message = document.createElement('p');
message.textContent = `Received: ${event.data}`;
document.getElementById('messages').appendChild(message);
};
// 监听错误事件
eventSource.onerror = function(event) {
console.error("Error occurred:", event);
};
</script>
</body>
</html>关键点说明:
EventSource:这是用于接收服务器推送事件的原生 JavaScript API。onmessage事件:监听从服务器接收到的消息,并将其显示在 HTML 页面上。onerror事件:监听可能发生的错误,例如与服务器的连接丢失。
4. 测试 SSE
启动 Go 服务器:
bashgo run server.go打开浏览器并访问
http://localhost:8080,你会看到页面上每秒更新当前时间。
5. SSE 的注意事项
- 单向通信:SSE 仅支持从服务器到客户端的单向数据流。如果需要双向通信,可以使用 WebSocket。
- 连接保持:SSE 是通过长连接实现的,浏览器会一直保持与服务器的连接,直到关闭或断开。
- 浏览器兼容性:大多数现代浏览器支持 SSE,但老版本的浏览器可能不支持,尤其是 Internet Explorer。你可以使用 polyfill 或者其他方法来处理不兼容的情况。
- 重连机制:浏览器会自动处理与服务器的连接断开问题,并尝试重新连接(默认是 3 秒重连),可以通过
retry字段来控制重试间隔。 - 最大连接数限制:由于 SSE 使用长连接,多个 SSE 流会消耗大量的资源。在大规模应用时,需要考虑负载均衡和连接数限制。
6. 总结
SSE 是一种简单而高效的技术,适用于单向数据流的应用场景,比如实时通知、消息推送、监控仪表板等。在 Go 中实现 SSE 相对简单,只需设置 HTTP 头并持续发送事件。通过结合客户端的 EventSource API,你可以轻松实现实时数据更新的功能。