go 实现 sse 推送的关键是确保连接稳定、事件实时、断连可检、并发可控;需手动设置响应头、及时 flush、检测 flush 错误、配置代理超时、防控 goroutine 泄漏。

Go 实现社交类 SSE 推送,关键不在“框架有多高级”,而在「连接不卡、事件不断、断连不漏、并发不崩」——用 net/http 原生写反而更可控;第三方库(如 r3labs/sse)省事但绕不开底层坑。
为什么 EventSource 一直卡在 connecting 状态
这不是前端问题,而是服务端响应头或刷新逻辑没到位。浏览器只认三件事:是否设了 Content-Type: text/event-stream、是否禁用了缓存、是否保持了长连接。
-
Content-Type必须在w.WriteHeader()之前设置,中间件(比如 gzip)可能覆盖它,别依赖全局中间件统一设 -
Cache-Control: no-cache缺失时,Chrome 或 Nginx 会缓存初始响应,后续所有data:都不会触发message事件 -
Connection: keep-alive不设,某些反向代理(如 ALB、Traefik 默认配置)会在空闲 60 秒后静默关闭连接 - 写了
fmt.Fprintf(w, "data: ...\n\n")却没调w.(http.Flusher).Flush()→ 数据卡在bufio.Writer缓冲区里,客户端永远等不到完整事件
如何安全地 flush 并检测客户端断连
别信 req.Context().Done() 在 HTTP/1.1 下的断连信号——它常滞后几秒甚至失效;真实断连第一手证据来自 Flush() 的 error。
- 每次
f.Flush()后必须检查 error:if err != nil && !errors.Is(err, syscall.EPIPE) && !errors.Is(err, net.ErrClosed),前者是客户端已关连接,后者是服务端主动关,其余错误要记录并退出 goroutine - 不要
defer f.Flush()—— 它只在 handler 返回时刷一次,起不到流式作用 - 用
json.Encoder替代手动拼data:字符串:避免引号转义错、JSON 格式非法导致前端触发error事件并自动重连 - 心跳不能省:每 25–30 秒发一条
: keepalive注释行(以冒号开头,客户端忽略),防运营商网关或防火墙因空闲超时断连
反向代理和超时配置必须同步调大
Go 服务端没崩,但用户收不到推送?大概率是代理层先动手了。
-
http.Server的WriteTimeout和ReadTimeout必须设为0(禁用),否则默认 30 秒就会静默关闭连接;改用ReadHeaderTimeout控制请求头读取(建议 10 秒) - Nginx 需配
proxy_read_timeout 300;(至少 5 分钟),且确保proxy_buffering off;,否则它会攒着data:不往下推 - Cloudflare 默认 100 秒超时,需在规则里设成「Origin Rules → Timeout → 300s」,否则不管 Go 怎么设都白搭
- ALB/ELB 要关掉「Idle timeout」或调到 ≥300,同时确认「Connection draining」未启用(它会拒绝新写入)
社交场景下的并发与资源泄漏防控
每个 SSE 连接开一个 goroutine 很自然,但没人断连就一直挂着,500 个连接 = 500 个 goroutine + 500 个 channel,内存和 fd 很快见底。
- 用带缓冲的
chan string(比如 cap=16)做 per-connection 消息队列,避免 goroutine 因写 channel 阻塞而卡住 flush - 给每个连接加
context.WithTimeout(ctx, 5*time.Minute),到期强制 close,防止僵尸连接堆积 - 用
sync.Map存活连接(key 是uintptr(unsafe.Pointer(&w))或自增 ID),别用普通 map + mutex —— 高频读写下锁竞争严重 - 别在 handler 里打
log.Printf每条推送 —— 日志 I/O 可能阻塞Flush(),导致客户端卡顿甚至断连
真正难的不是发数据,是让每条 data: 都准时、完整、不丢、不卡地落到浏览器 EventSource 的 onmessage 回调里——所有环节都要对齐:Go 的 flush、代理的 timeout、浏览器的解析规则、网络中间设备的耐心。漏掉任意一环,社交 feed 就变成“偶尔动一下”的幻灯片。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











