[Go实战]:SSE消息推送
前言
在现代Web开发中,前后端分离已成为主流趋势。为了实现实时数据推送,Server-Sent Events (SSE) 是一种高效且易于实现的技术。本文将介绍如何在Go语言中实现SSE服务端,并在前端使用JavaScript进行集成,实现一个完整的实时数据推送系统
1. SSE简介
Server-Sent Events (SSE) 是HTML5的一项技术,用于服务器向浏览器自动发送更新信息。SSE的主要特点包括:
- 单向通信:数据流是从服务器到客户端的单向流动。
- 自动重连:如果连接断开,客户端会自动尝试重新建立连接。
- 简单易用:相比WebSocket,SSE的API更简单,更容易上手。
- 文本格式:SSE的数据是以文本形式发送的,通常为JSON或纯文本。
2. 后端实现
2.1 设置静态文件目录
首先,我们需要设置静态文件目录,以便前端页面和其他静态资源可以被正确加载。
package main
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
func main() {
// 设置静态文件目录
fs := http.FileServer(http.Dir("./static"))
http.Handle("/", fs)
// 设置 SSE 处理器
http.HandleFunc("/events", handleEvents)
// 启动服务器
http.ListenAndServe(":8080", nil)
}
2.2 设置SSE处理器
接下来,我们创建一个SSE处理器来处理客户端的SSE请求,并设置正确的响应头。
func handleEvents(w http.ResponseWriter, r *http.Request) {
// 设置 CORS 头部
//w.Header().Set("Access-Control-Allow-Origin", "*")
//w.Header().Set("Access-Control-Allow-Methods", "GET")
//w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
// 设置响应头
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
// 模拟数据流
for {
// 生成推送消息
data, _ := json.Marshal(map[string]string{"timestamp": time.Now().Format(time.RFC3339)})
_, err := fmt.Fprintf(w, "data: %s\n\n", data)
if err != nil {
// 客户端断开连接,输出日志
fmt.Println("Client disconnected:", err)
return
}
// 刷新缓冲区
if flusher, ok := w.(http.Flusher); ok {
flusher.Flush()
}
// 检查是否应该关闭连接
select {
case <-r.Context().Done():
return
default:
time.Sleep(2 * time.Second) // 每2秒发送一次消息
}
}
}
2.3 启动HTTP服务器
在上面的代码中,我们定义了两个路由:
- /:处理静态文件请求。
- /events:处理SSE请求。
3. 前端实现
3.1 创建前端页面
创建一个名为 index.html 的文件,用于展示接收到的消息。将该文件放在 main.go 同级地 static 目录下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE 案例</title>
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background-color: #f0f0f0;
}
.container {
text-align: center;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 600px;
width: 100%;
box-sizing: border-box;
}
h1 {
color: #333;
margin-bottom: 20px;
}
#messages {
height: 300px; /* 固定高度 */
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
background-color: #f9f9f9;
color: #555;
margin-top: 20px;
box-sizing: border-box;
}
p {
margin: 5px 0;
font-size: 16px;
}
#clock {
font-size: 18px;
color: #777;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>服务器发送事件示例</h1>
<div id="messages"></div>
<div id="clock"></div>
</div>
<script>
// 创建一个新的 EventSource 实例
const eventSource = new EventSource('/events');
// 监听消息事件
eventSource.onmessage = function (event) {
const newMessage = document.createElement('p');
newMessage.textContent = 'New message: ' + event.data;
document.getElementById('messages').appendChild(newMessage);
// 滚动到底部
const messagesDiv = document.getElementById('messages');
messagesDiv.scrollTop = messagesDiv.scrollHeight;
};
// 监听错误事件
eventSource.onerror = function (error) {
console.error('EventSource failed:', error);
eventSource.close();
};
</script>
</body>
</html>
- 创建EventSource对象:const eventSource = new EventSource('/events'); 创建一个EventSource对象,连接到服务器的 /events 路由。
- 处理消息:eventSource.onmessage 事件处理器用于处理从服务器接收到的消息,并将其显示在页面上。
- 处理错误:eventSource.onerror 事件处理器用于处理连接错误,并在发生错误时关闭连接。
- 自动滚动:每次接收到新消息时,自动滚动到消息列表的底部,确保用户始终能看到最新的消息。
4. 运行项目
4.1 启动服务:
go run main.go
打开浏览器,访问 http://localhost:8080,你应该能看到每两秒钟从服务器推送的一条新消息,且页面内容全屏自适应,样式更加美观。
5 注意事项
5.1 客户端连接限制
- 浏览器对每个域名下的SSE连接数有限制。大多数现代浏览器允许每个域名最多6个并发连接。如果超过这个限制,新的连接将会被阻塞,直到有连接关闭。
- 如果你的应用需要支持更多的并发连接,可以考虑使用子域名或负载均衡来分散连接。
5.2 服务器资源管理
- 每个SSE连接都会占用服务器的一个goroutine,因此需要合理管理服务器资源。如果预期会有大量并发连接,建议使用连接池或其他资源管理机制。
- 可以通过设置超时、心跳检测等方式来管理长时间未活动的连接,避免资源浪费。
5.3 错误处理和重连
- 客户端可以通过 onerror 事件处理器来处理连接错误,并实现自动重连逻辑。
- 服务器端可以在连接关闭时发送适当的错误信息,帮助客户端更好地处理异常情况。
5.4 安全性
- 确保SSE接口的安全性,避免暴露敏感数据。可以使用HTTPS来加密传输数据。
- 对于需要认证的场景,可以在SSE请求中携带认证信息,例如使用HTTP头部或Cookie。
总结
本文详细介绍了如何在Go语言中实现SSE(Server-Sent Events)服务端,并在前端使用JavaScript进行集成,实现一个完整的实时数据推送系统。SSE作为一种轻量级的实时通信技术,非常适合那些只需要从服务器向客户端发送数据的应用场景。希望本文能对你有所帮助!