背景
最近在项目中遇到两个 SSE (Server-Sent Events) 相关的问题,一个是业务逻辑层面的”提前结束”,一个是基础设施层面的”连接超时”。记录一下排查和解决过程,供大家参考。
什么是 SSE?
Server-Sent Events (SSE) 是 HTML5 推出的服务端推送技术,允许服务器通过 HTTP 协议向浏览器单向推送数据。相比 WebSocket,SSE 更轻量,适合服务端→客户端的简单实时场景。
SSE 的特点:
- 单向通信:服务器 → 客户端单向推送
- 基于 HTTP:无需 WebSocket 协议开销
- 自动重连:浏览器原生支持
- 实现简单:相比 WebSocket 更适合简单场景
典型场景:实时通知、进度更新、行情推送、日志流。
坑一:SSE 流提前结束
现象
报告生成进度才 33%,前端就收到”完成”通知,实际内容不完整。
排查
检查代码发现,判断任务完成的逻辑是:
// 错误:用外部服务的 duration_ms 字段判断
if data["duration_ms"] != nil {
isCompleted = true
}
问题在于:外部服务在进度很低时就返回了 duration_ms 字段,导致客户端误判为已完成。
解决
要有自己的完成判断逻辑,别全信第三方:
// 正确:验证 sections 数量
if len(sections) >= expectedSections {
isCompleted = true
}
关键点:不要依赖外部服务的”完成信号”,要有自己的完成标准。
坑二:SSE 连接 30 秒超时
现象
长连接被网关切断,报告生成中断。
排查
默认的 HTTP 客户端有响应头超时限制:
// 默认配置
&http.Client{
Timeout: 30 * time.Second, // 默认超时
}
解决
SSE 场景下需要禁用所有超时:
sseClient := &http.Client{
Timeout: 0, // 无超时
Transport: &http.Transport{
ResponseHeaderTimeout: 0,
// 其他超时配置也要关闭
},
}
关键点:SSE 流要禁用所有超时,靠应用层心跳保活。
总结
SSE 是轻量级的服务端推送方案,但使用时要注意:
- 要有自己的完成判断逻辑:别全信第三方服务的”完成信号”
- 长连接要处理超时:禁用默认 HTTP 超时,靠应用层保活
希望这篇文章能帮助大家避免踩坑。