go服务端实现sse必须显式调用http.flusher.flush(),否则数据滞留缓冲区导致客户端收不到事件;需设置content-type、cache-control、connection响应头,并严格遵循data: xxx\n\n格式,同时监听req.context().done()及时退出goroutine。

Go 服务端写 SSE 必须显式 Flush
不调用 Flush(),客户端永远收不到任何事件。Go 的 http.ResponseWriter 默认带缓冲,fmt.Fprintf(w, "data: hello\n\n") 只是把字节塞进内存缓冲区,不会发到网络上。
- 必须先断言:
flusher, ok := w.(http.Flusher),失败就返回错误 - 每次写完都要
flusher.Flush(),不能只在 handler 结束时 flush - 别用
defer flusher.Flush()——它只执行一次,起不到流式作用 - 如果用了
bufio.Writer包裹响应体(比如某些中间件),要确保它也 flush,但更推荐直接用原生Flusher
响应头缺一不可,浏览器才会认成 SSE
漏掉任意一个关键 header,EventSource 状态会卡在 connecting 或直接静默失败,连 error 事件都不触发。
-
Content-Type: text/event-stream—— 缺少这个,浏览器根本不走 SSE 解析逻辑 -
Cache-Control: no-cache—— 浏览器可能缓存初始响应,后续事件全丢 -
Connection: keep-alive—— 防代理(Nginx、Cloudflare)或负载均衡器中途断连 - 不要额外加
Content-Encoding: gzip—— HTTP/2 下压缩会攒包,破坏流式实时性
data: 格式错一个字符,整条事件就被丢弃
SSE 协议对换行、空格、冒号后空格极其敏感。Chrome 和 Firefox 不会报错,只会跳过非法行,你根本不知道哪条没发出去。
- ✅ 正确:
data: hello\n\n(:后有空格,结尾两个\n) - ❌ 错误:
data:hello\n\n(:后无空格,部分浏览器不识别) - ❌ 错误:
data: hello\n(少一个\n,事件不终止,后续内容被吞) - ❌ 错误:
data: hello\r\n\r\n(Windows 换行符,应统一用\n) - 多行数据要拆成多个
data:行:data: line1\ndata: line2\n\n
客户端断连后 goroutine 必须主动退出
Go 不会自动回收已断开的 SSE 连接 goroutine。如果只是循环写 + sleep,连接断了还在后台跑,内存和 goroutine 会越积越多。
- 用
req.Context().Done()监听断连信号(http.CloseNotifier已弃用) - 每次写之前检查:
select { case - 配合
time.Ticker发心跳(如: ping\n\n)可提前暴露断连,避免死等 - 别在 handler 里直接
time.Sleep模拟延迟——它会阻塞整个 goroutine,影响 flush 及时性
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











