Fiber 的 ctx.Response().Writer 不能直接当 http.Flusher 用,因其基于 fasthttp.Response 不实现该接口,须改用 ctx.Response().Flush();设置 Header 必须在写响应体前完成,且需禁用 CompressHandler;广播 SSE 应存 BodyWriter 而非 ctx;Nginx 需关闭 proxy_buffering 并调高超时。

为什么 Fiber 的 ctx.Response().Writer 不能直接当 http.Flusher 用
Fiber 默认用的是自定义的 fasthttp.Response,它不实现 Go 标准库的 http.Flusher 接口,所以你不能直接对 ctx.Response().Writer 做 w.(http.Flusher) 类型断言——会 panic 或静默失败。
必须用 Fiber 提供的 ctx.Response().Flush() 方法,它是 fasthttp 原生支持的流式刷出机制。标准 net/http 的那一套(比如检查 http.Flusher)在这里完全不适用。
- 别写:
flusher, ok := ctx.Response().Writer.(http.Flusher)—— 这永远是ok=false - 要写:
ctx.Response().Flush(),且每次写完 event 后立刻调用 - 确保没启用
CompressHandler中间件,它会包裹响应体、破坏text/event-stream流式结构
ctx.Set() 必须在 ctx.SendString() 之前调用,否则 header 被忽略
Fiber 的 header 设置是惰性的,只有在首次写响应体前才真正生效。如果你先调 ctx.SendString("data: hello\n\n"),再调 ctx.Set("Content-Type", "text/event-stream"),浏览器收不到正确 header,EventSource 就卡在 connecting 状态。
- 顺序必须是:
ctx.Set("Content-Type", "text/event-stream")→ctx.Set("Cache-Control", "no-cache")→ctx.Set("Connection", "keep-alive")→ 再开始写事件 - 别在中间件里统一设这些 header——Fiber 的中间件执行时机可能晚于 header 发送时机,尤其搭配
Recover或Logger时容易踩坑 - 如果用了
ctx.Status(200),也得放在所有Set()之后,否则状态码可能被覆盖
怎么安全地广播 SSE 事件给多个客户端而不 panic
Fiber 每个请求默认跑在一个 goroutine 里,但你不能把 ctx 存进全局 map 并跨 goroutine 调用它的方法——ctx 不是线程安全的,且底层 fasthttp.RequestCtx 在 handler 返回后就失效了。
立即学习“go语言免费学习笔记(深入)”;
- 正确做法:只存
ctx.Response().BodyWriter()返回的io.Writer(通常是*fasthttp.writer),它是可并发写的 - 用
sync.Map存clientID → io.Writer,广播时遍历并调w.Write([]byte("data: ...\n\n"))+fasthttp.Response.Flush() - 每次写完必须检查 error:如果返回
fasthttp.ErrGetConnTimeout或io.ErrClosedPipe,说明客户端已断开,立即从sync.Map中删掉该 writer - 别依赖
ctx.Context().Done()判断断连——fasthttp 的 context 不像 net/http 那样能及时反映连接关闭,真实信号来自Write()或Flush()的 error
心跳和超时配置:Nginx + Fiber 组合下最容易漏的三处
即使 Fiber 侧代码全对,前端仍反复重连,90% 是反向代理或服务器空闲超时导致的。Fiber 自身不暴露 IdleTimeout,得靠底层 fasthttp.Server 配置,而 Nginx 默认会掐掉 60 秒无数据的连接。
- Fiber 启动时必须传入自定义
fasthttp.Server:app.Server = &fasthttp.Server{ReadTimeout: 0, WriteTimeout: 0, IdleTimeout: 5 * time.Minute} - Nginx 配置里必须显式放行:
proxy_buffering off;、proxy_cache off;、proxy_read_timeout 300;(至少匹配 Fiber 的IdleTimeout) - 每 15–25 秒主动发一次心跳:
ctx.Response().WriteString(":ping\n\n")+ctx.Response().Flush(),注意用冒号开头的注释行,客户端自动忽略,但能防代理超时
最常被忽略的是 proxy_buffering off —— 它一开,Nginx 就会攒够 4KB 才转发,SSE 事件直接卡住,前端等不到第一个 data:。


















