How to implement Server-Sent Events in Go
原文链接:packagemain.tech/p/implement…
原文作者:Julien Singler
译者:菜小鸟魔王
01 Introduction
服务器推送技术(Server-Sent Events, SSE)是一种高效能的解决方案,它支持服务器向客户端进行实时且单向的数据传输。本文将带领读者深入了解如何在 Go 语言中应用 SSE,我们将讨论其诸多优点、适用场景,并通过具体案例展示其实现过程。
02 什么是 Server-Sent Events 技术?
SSE 技术允许服务器通过持续的 HTTP 连接向客户端推送数据。
与双向通信的 WebSockets 相比,SSE 只支持单向数据流,因此它在实现上更为简洁,特别适用于那些只需服务器向客户端实时发送数据更新,而不需要客户端回传信息的场景。
构建一个采用 SSE 的 Web 应用并不复杂。需要在服务器上编写一些代码来向前端发送事件流,而客户端在接收事件的处理逻辑上,与使用 websockets 时非常相似。不过,由于这是一种单向连接,所以并不支持从客户端向服务器发送事件。
03 SSE 的优点
-
简洁:SSE 在实现上比 WebSockets 更为简单。
-
原生浏览器兼容:SSE 无需额外配置,即可在多数现代浏览器上直接使用。
-
自动重连功能:当连接意外断开时,客户端能够自动进行重连尝试。
-
高效:SSE 通过单一 HTTP 连接进行数据传输,有效减少了服务器和客户端的资源消耗。
04 用 GO 实现 SSE
让我们用 Go 创建一个简单的 SSE 服务器:
package main
import (
"fmt"
"net/http"
"time"
)
func sseHandler(w http.ResponseWriter, r *http.Request) {
// Set http headers required for SSE
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
// You may need this locally for CORS requests
w.Header().Set("Access-Control-Allow-Origin", "*")
// Create a channel for client disconnection
clientGone := r.Context().Done()
rc := http.NewResponseController(w)
t := time.NewTicker(time.Second)
defer t.Stop()
for {
select {
case <-clientGone:
fmt.Println("Client disconnected")
return
case <-t.C:
// Send an event to the client
// Here we send only the "data" field, but there are few others
_, err := fmt.Fprintf(w, "data: The time is %s\n\n", time.Now().Format(time.UnixDate))
if err != nil {
return
}
err = rc.Flush()
if err != nil {
return
}
}
}
}
func main() {
http.HandleFunc("/events", sseHandler)
fmt.Println("server is running on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println(err.Error())
}
}
05 事件流格式
-
每个事件都是以一对换行符结尾的文本块形式发送的,即以 “\n\n” 结尾。
-
负责发送事件的服务器端脚本需要使用 MIME 类型 “text/event-stream” 来响应。
-
为了调试方便,我们可以添加注释。在一行的开头使用冒号(:)就是添加注释,这样的代码行会被忽略。
接收到的每个消息都包含以下字段组合,每个字段占据一行:
-
event - 用来标识所描述事件类型的字符串。
-
data - 消息的数据字段。
-
id - 用于设置 EventSource 对象的最后一个事件 ID 值的事件 ID。
-
retry - 重连的时间间隔。
在前端,需要使用一个名为 EventSource 的对象:
<!doctype html>
<html>
<body>
<ul id="list"></ul>
</body>
<script type="text/javascript">
const eventSrc = new EventSource("http://127.0.0.1:8080/events");
const list = document.getElementById("list");
eventSrc.onmessage = (event) => {
const li = document.createElement("li");
li.textContent = `message: ${event.data}`;
list.appendChild(li);
};
</script>
</html>
欲知更多详情,请点击此处。以下是浏览器控制台中的显示内容:
06 实现 SSE 的关键组件
-
头部设置:需要设定特定的头部信息以建立 SSE 连接。
-
事件循环:服务器将不断地向客户端推送事件。
-
数据即时发送:利用 http.Flusher 接口来保证数据能够被即时发送。
-
客户端断开处理:以恰当的方式处理客户端的断开连接。
07 Golang 中 SSE 的实践指导原则
-
错误处理:为连接问题实现健壮的错误处理机制。
-
事件格式化:使用结构化格式(例如 JSON)来定义事件。
-
重连策略:客户端在连接断开时应该有一个合理的重连策略,比如使用指数退避算法来避免频繁的重连尝试。
-
负载均衡:在服务器端,如果应用程序需要处理大量并发连接,应该使用负载均衡器来分配流量。
08 SSE 的使用场景
- 实时仪表板
- 体育赛事实时得分
- 社交媒体动态
- 股票市场行情显示器
- 长时间运行任务的进度指示器
09 Conclusion
Server-Sent Events(简称 SSE)为 Golang 提供了一种高效且简单的方法来实现实时服务器到客户端的通信。利用 SSE,开发人员可以轻松构建出响应速度快且动态的 Web 应用,同时还能保持最小的开销和复杂度。
在构建基于 SSE 的应用程序时,请务必考虑到可扩展性、错误处理以及客户端的实现,以确保实时通信系统的健壮性和效率。