必须先调用w.writeheader()和w.(http.flusher).flush()才能进入等待状态,否则客户端无法开始长轮询;需select监听datachan、ctx.done()和time.after三路信号;channel容量至少100且发送需非阻塞;唯一可靠断连信号是req.context().done()。

Go 语言里写长轮询,最常踩的坑不是逻辑没想清,而是 w.WriteHeader 漏了、Flush() 忘了、time.Sleep 用上了、string(counter) 写错了——这些看似小动作,上线后直接导致客户端卡 pending、goroutine 泄漏、消息乱码或连接被 Nginx 静默掐断。
为什么必须先 WriteHeader + Flush 才能进等待状态
HTTP/1.1 客户端只有收到响应头(含状态码),才会认为请求已“建立”,进而开始等待 body。Go 的 ResponseWriter 默认缓冲全部输出,如果只调 w.Write([]byte{}) 或跳过 w.WriteHeader,客户端永远收不到 header,也就不会进入“长轮询等待”流程,轻则卡在 pending,重则被代理判为超时返回 504。
- 必须在任何阻塞操作(如
)前调用 <code>w.WriteHeader(http.StatusOK) - 紧接着调用
w.(http.Flusher).Flush()强制刷出 header;HTTP/2 不支持 Flusher,生产环境需确认协议版本 - flush 后不能再调
w.WriteHeader,否则 panic: “http: multiple response.WriteHeader calls” - 不 flush 就 return,Nginx 很可能在 60 秒后直接断连,而服务端 goroutine 还在 channel 上挂起
select 监听三路信号,不能只靠 time.After
只监听 是伪长轮询:它不感知客户端是否已关闭页面、网络是否中断、Nginx 是否提前切断连接。真实场景中,这三个退出条件必须共存且互不干扰。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 监听
:有新消息立刻响应,保证低延迟 - 监听
:由 <code>req.Context()触发,覆盖浏览器关闭、fetch abort、Nginx 断连等所有主动断开场景 - 监听
:兜底超时,建议比 Nginx 的 <code>proxy_read_timeout小 5–10 秒(如 Nginx 设 240s,这里设 235s) - 三者用
select并发等待,任一满足即退出阻塞,避免 goroutine 泄漏
channel 容量、发送方式与并发安全
用 chan string 做事件通道很常见,但容量和发送逻辑稍有偏差,高并发下就会卡死推送方或 panic。
- 容量至少设为
100(如make(chan string, 100));设为 1 时,若接收方未及时读取,推送方会阻塞在messages ,拖垮整个消息流 - 推送方写入前必须非阻塞:用
select { case ch ,失败即跳过,不强求送达 - 不要
close(ch)清理 channel;应从全局sync.Map或加锁 map 中delete()移除,让 goroutine 自然退出 - 注册/注销 channel 时,务必成对操作;handler 返回前不清理,内存持续增长
客户端断连和服务端清理的关键判断点
HTTP/1.1 下服务端无法主动探测客户端存活,ResponseWriter 的底层连接状态不可信——Write 成功不代表数据已送达。唯一可靠信号是 req.Context().Done()。
- 每次 handler 进入就检查
if req.Context().Err() != nil { return },尤其在Flush()之后、写 body 前再查一次 - 别依赖
http.Server.IdleTimeout:它只对空闲连接计时,而长轮询请求始终处于“处理中”,不触发 idle 清理 - 真正要调的是
ReadTimeout和WriteTimeout,但它们也得比业务等待时间长(如最长等 235s,这两个 timeout 至少设 240s),否则 server 会主动关连接 - Nginx 必须配
proxy_read_timeout 240和proxy_buffering off,否则它会在 60 秒默默断连,而你的 goroutine 还在等一个永远不会来的消息
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










