使用http.Flusher实时推送需先类型断言w是否支持,设置Content-Type,每次写入后调用Flush();推荐json.Encoder避免手动拼JSON出错;注意Nginx配置、超时控制、客户端断连检测及NDJSON/SSE格式选择。

Go HTTP handler 怎么用 http.Flusher 实时推送数据
必须确认 ResponseWriter 支持 http.Flusher,否则调用 Flush() 会 panic。不是所有环境都支持——比如某些反向代理(Nginx 默认)、Serverless 平台(Vercel、Cloudflare Workers)或测试用的 httptest.ResponseRecorder 都不实现它。
实操建议:
- 先做类型断言:
if f, ok := w.(http.Flusher); ok { f.Flush() },别直接断言后调用 - 确保 Content-Type 已写入(
w.Header().Set("Content-Type", "text/event-stream")或"application/json"),否则部分浏览器可能缓冲整块响应 - 写完每条数据后立即调用
f.Flush(),但别太频繁(如循环里每字节 flush),会拖慢服务端并增加 TCP 包开销 - 如果走 Nginx,需显式开启流式支持:
proxy_buffering off;、chunked_transfer_encoding on;
为什么 json.Encoder + Flush() 比 fmt.Fprintf 更稳
手动拼 JSON 容易漏逗号、引号转义错、结构不合法;而 json.Encoder 自动处理编码、分隔和错误,配合 Flush() 能保证每次输出都是完整、可解析的 JSON 值(如 SSE 中的 data: {...} 或 NDJSON 行)。
常见错误现象:前端收到半截 JSON、解析失败、EventSource 自动关闭连接。
立即学习“go语言免费学习笔记(深入)”;
实操建议:
- 用
json.NewEncoder(w)初始化一次,复用它调用Encode() - 每次
Encode()后跟f.Flush(),不要等 defer 或函数结束 - 避免在 encode 前写额外字符串(如
w.Write([]byte("data: "))),除非你完全控制格式(如 SSE) - 如果要发 SSE,记得加
w.Header().Set("Content-Type", "text/event-stream")和换行结尾(\n\n)
流式接口遇到超时或客户端断连怎么检测
Go 的 http.ResponseWriter 不主动暴露连接状态,但可通过 context.Done() 和底层连接错误间接判断。典型表现是 Write() 或 Flush() 返回 broken pipe、connection reset by peer 等错误。
实操建议:
- 每次
Write()/Flush()后检查 error:if err != nil && !errors.Is(err, syscall.EPIPE) && !errors.Is(err, net.ErrClosed) { /* 处理其他错误 */ } - 监听
r.Context().Done(),配合select判断是否客户端取消请求 - 不要依赖
http.CloseNotify()(已弃用),它在 Go 1.19+ 中不可靠且被移除 - 流式接口建议设较短的
WriteTimeout(如 30s),防止 goroutine 泄露
Stream 返回 JSON 数组 vs 每次一个对象(NDJSON)的区别
返回 [{},{},{}] 是非法流式响应——JSON 数组无法增量解析;必须用 NDJSON(每行一个 JSON 对象)或 SSE(data: {...}\n\n)才能被客户端边收边解。
性能与兼容性影响:
- NDJSON 简单通用,前端可用
fetch().body.getReader()流式读取,Node.js/Python 客户端也容易处理 - SSE 浏览器原生支持
EventSource,但只支持 GET,且服务端需维持长连接头(Cache-Control: no-cache、Connection: keep-alive) - 别用
application/json响应流式数据——多数 JSON 解析器会等 EOF,导致阻塞 - 移动端 WebView 或旧版 Safari 对
text/event-stream支持不稳定,NDJSON + 手动解析更可控
流式不是加个 Flush() 就完事。真正难的是错误传播、连接生命周期管理、客户端兼容性兜底——这些地方一漏,接口就变成偶发卡死或静默失败。


















