learning-labs:SSE 实践笔记与实现要点
背景
在 @learning-labs 里,我整理了一套 SSE(Server-Sent Events)的学习与实践内容,目标是用最小完整例子把「概念、实现、测试」贯通起来,并对比它和 WebSocket 的取舍边界。
这一专题放在 learning-labs/sse/,源码地址:
https://github.com/wfnking/learning-labs/tree/master/sse
包含:
go-example/:Go 语言的完整 SSE 服务端 + 浏览器测试页面node-example/:Node.js 命令行 SSE 客户端README.md:概念、格式、实现要点与使用场景
SSE 的核心特点(实践视角)
- 单向推送:服务器 → 客户端,适合通知、日志、进度条等场景
- 基于 HTTP:
Content-Type: text/event-stream,无需额外协议 - 自动重连:浏览器 EventSource 内置重连,支持
retry与Last-Event-ID - 命名事件:通过
event:字段区分不同事件类型
当你只需要服务端推送而不需要双向实时交互时,SSE 会比 WebSocket 更简单、可维护。
实现要点:服务端
1) 响应头必须正确
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
2) 消息格式统一
func formatSSEMessage(event, data string) string {
if event != "" {
return fmt.Sprintf("event: %s\ndata: %s\n\n", event, data)
}
return fmt.Sprintf("data: %s\n\n", data)
}
3) 保持连接 + 及时 Flush
SSE 连接是长连接,必须确保:
- 连接不被中断
- 发送后立刻
Flush() - 客户端断线后清理资源
4) Hub 模式处理并发
为了避免多个客户端阻塞,学习项目里用了简单的 Hub(广播中心)模型:
type SSEHub struct {
clients map[string]*SSEClient
register chan *SSEClient
unregister chan *SSEClient
broadcast chan string
}
实践案例(learning-labs/sse)
Go 端点设计
/events:基础广播/clock:每秒推送当前时间/stock:模拟股票数据(JSON)
Node 客户端
通过命令行脚本验证不同事件流:
basic.js:基础连接与消息接收clock.js:实时时钟订阅stock.js:JSON 解析与渲染
SSE vs WebSocket:我的取舍标准
- 只需要服务端推送 → 选 SSE
- 需要双向交互或二进制传输 → 选 WebSocket
SSE 的可维护性与浏览器原生支持,是很多轻量实时场景的优势。
常见坑点(实践中最容易踩)
- 代理缓冲:反向代理可能会缓冲响应,导致“推送无效”
- 浏览器连接限制:HTTP/1.1 下同域最多 6 条 SSE 连接
- Flush 忘记调用:不 Flush 就不会立刻看到消息
- 未清理断线:容易导致内存泄漏
快速开始
cd learning-labs/sse/go-example
go run main.go
浏览器访问:http://localhost:8888
或用 Node 客户端测试:
cd learning-labs/sse/node-example
npm install
npm run basic
结语
这次在 @learning-labs 的 SSE 实践更像是一个“最小可运行的知识样本”:
既保留了协议细节,又能通过完整示例把 SSE 的价值感知出来。
如果你也在搭建实时系统,建议把 SSE 当作「轻量级推送」的首选方案之一。