Iris 中长连接本质是 HTTP 流式响应,需手动设响应头、禁缓冲、调用 Flush() 并按 SSE 格式写数据;必须检查 write 错误以检测客户端断连,避免 goroutine 卡死和内存泄漏。

长连接在 Iris 中本质是 HTTP 流式响应,不是“开启某个开关”
Iris 没有 SseEmitter 或 keep-alive 配置项这类抽象封装——它把长连接交由底层 http.ResponseWriter 控制。你得自己设响应头、禁缓冲、手动 Flush()、按格式写数据。所谓“处理长连接”,实际就是维持一个未关闭的 HTTP 响应流。
必须设置的响应头和禁用缓冲,否则浏览器根本不认
常见错误是只写了 data: 却没配对响应头,导致前端 EventSource 一直 pending 或直接报错 net::ERR_INCOMPLETE_CHUNKED_ENCODING。
-
ctx.Response().Header().Set("Content-Type", "text/event-stream")—— 缺少这个,浏览器不会进入流模式 -
ctx.Response().Header().Set("Cache-Control", "no-cache")—— 否则某些代理或浏览器会缓存首条消息,后续推送不触发回调 -
ctx.Response().Flush()必须在首次写入前调用 —— 否则响应头压在缓冲区,连接卡住,EventSource等不到初始响应就超时断开
用 ctx.Stream() 简化定时推送,但要注意它默认缓冲
ctx.Stream() 是 Iris 提供的便捷入口,适合做心跳、时钟、简单状态广播等场景。但它内部仍走标准流逻辑,不自动帮你 Flush(),也不处理断连。
- 必须显式调用
ctx.Response().Flush()在循环开始前和每次fmt.Fprintf()后 - 每条消息结尾必须是
"data: %s\n\n"(两个换行),缺一个\n就无法触发前端message事件 - 别在循环里用
time.Sleep(1 * time.Second)控节奏——若客户端断连,goroutine 会卡死;要配合ctx.Done()检查上下文是否已取消
客户端断连检测不能只靠 ctx.Done(),还要检查 write 错误
HTTP 长连接下,客户端关页、网络中断、Nginx 超时断开,服务端往往感知滞后。只监听 ctx.Done() 不够可靠,因为有些中间件或反向代理(如 Nginx 默认 60s keepalive_timeout)会静默关闭连接,而 Go 的 http.ResponseWriter 还没收到 EOF。
- 每次
fmt.Fprintf(ctx.ResponseWriter(), ...)后,检查返回的error—— 若是"write: broken pipe"或"write: connection reset by peer",说明客户端已掉线,应立即break循环并退出 goroutine - 用
sync.Map或map[chan struct{}]*Client管理活跃连接时,记得在退出前从 map 中删掉对应项,避免内存泄漏 - 别依赖
responseWriter.Hijack()—— Iris 的Context不暴露原生ResponseWriter,且 Hijack 在 HTTP/2 下不可用,兼容性差
真正难的不是写通第一条消息,而是让成百上千个长连接稳定存活数小时——这取决于你如何处理 write 错误、何时清理失效连接、以及反向代理是否透传了 Connection: keep-alive 和超时配置。这些细节不在框架里,而在你的 handler 循环中。


















