ctx.json和ctx.sendstring会失败,因为fiber基于fasthttp默认写完即关连接,而sse要求长期连接、分块写出、固定响应头且禁用缓存;调用二者会触发ctx.response.end()导致连接终止,浏览器报net::err_incomplete_chunked_encoding。

不能用 ctx.SendString 或 ctx.JSON,必须手动接管响应流并持续 Flush(),否则连接秒断、浏览器报 net::ERR_INCOMPLETE_CHUNKED_ENCODING。
为什么 ctx.JSON 和 ctx.SendString 会失败
Fiber 基于 fasthttp,默认写完响应就关闭连接。SSE 要求连接长期存活、数据分块写出、响应头固定且不可缓存。调用 ctx.JSON 会自动设置 Content-Type: application/json、写入完整体、然后调用 ctx.Response.End() —— 这直接终结了 HTTP 连接,后续事件根本发不出去。
- 错误现象:浏览器
EventSource反复触发error事件,控制台显示net::ERR_INCOMPLETE_CHUNKED_ENCODING - 根本原因:
fasthttp不暴露原生Write+Flush接口,Fiber 封装层又默认“一写就关” - 绕过方式:必须用
c.Context().SetBodyStreamWriter接管整个响应体流
手动设置响应头与流写入(Fiber v2.50+)
关键不是“怎么发数据”,而是“怎么不让连接死”。以下头字段缺一不可:
-
Content-Type: text/event-stream:告诉浏览器这是 SSE 流 -
Cache-Control: no-cache:禁用代理和浏览器缓存,否则事件被卡住 -
Connection: keep-alive:显式要求保持连接 -
X-Accel-Buffering: no:Nginx 场景下禁用其内部缓冲(否则事件延迟数秒才到前端)
写入时注意:data: 行末必须跟两个 \n,例如 "data: {\"count\":1}\n\n";每次写完必须调用 w.Flush(),否则数据滞留在 bufio.Writer 缓冲区里出不去。
Fiber v3 的 sse 中间件怎么用
v3 内置了 github.com/gofiber/fiber/v3/middleware/sse,它把底层细节封装好了,但只做传输层的事——不处理用户认证、频道管理、消息存储这些应用逻辑。
- 必须传
Config.Handler:它接收*sse.Stream,你往里面写事件即可 -
Retry字段会在流开头自动写retry: 5000,让浏览器断连后 5 秒重试 - 事件格式由
stream.Event()自动组装,不用手拼data:和换行符 - 心跳注释(
: ping\n\n)和断连检测(基于Flush()错误)已内置
示例中没写 stream.Close() 是因为中间件会在连接关闭时自动清理;你只需专注业务数据推送逻辑。
容易被忽略的生产细节
本地跑通不等于线上可用。Nginx 默认 proxy_read_timeout 是 60 秒,没配就会在 1 分钟后主动断开 SSE 连接;Gunicorn 默认超时是 30 秒,也得调大。更隐蔽的是:如果生成器里用了 time.Sleep,在同步 Fiber 应用里会阻塞整个 goroutine,导致其他请求排队 —— 正确做法是用 time.AfterFunc 或启动独立 goroutine 推送,别让流写入逻辑阻塞主线程。











