Go语言实现每2秒触发SSE遇延迟问题求助
解决Go语言SSE服务每2秒稳定推送数据的问题
问题根源分析
- 原始代码仅推送一次就断开连接:你的初始
handleSse函数只发送一次数据就结束,客户端EventSource发现连接断开后会自动重连(默认重连间隔约3秒),叠加网络延迟后就出现了你看到的5.4秒间隔——这并非服务端主动推送的间隔,而是客户端重连的间隔。 - 尝试的循环写法逻辑错误:你写的循环会瞬间完成10次数据推送,客户端一次性接收所有数据后连接断开,再次触发重连;添加
time.Sleep后,整个handler会阻塞执行完所有循环,期间客户端无法收到分段数据,且连接关闭后重连间隔进一步累积,导致总延迟变长。
修正后的服务端代码
package main import ( "fmt" "log" "net/http" "time" "github.com/rs/cors" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/sse", handleSse) c := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete, http.MethodPut}, AllowCredentials: true, }) handler := c.Handler(mux) log.Fatal(http.ListenAndServe(":6969", handler)) } func handleSse(w http.ResponseWriter, r *http.Request) { // 设置SSE响应头 w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") // 断言获取Flusher接口,用于强制刷新缓冲区 f, ok := w.(http.Flusher) if !ok { http.Error(w, "SSE not supported", http.StatusBadRequest) return } // 监听客户端断开信号,避免goroutine泄漏 ctx := r.Context() // 创建2秒间隔的定时器 ticker := time.NewTicker(2 * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): // 客户端断开连接,退出循环释放资源 return case <-ticker.C: // 发送符合SSE规范的数据(格式:data: 内容\n\n) fmt.Fprintf(w, "data: %v\n\n", time.Now().Format("2006-01-02 15:04:05")) // 强制刷新缓冲区,确保数据立即推送给客户端 f.Flush() } } }
关键修正点说明
- 定时推送+长连接保持:使用
time.Ticker实现精准的2秒间隔推送,替代循环+sleep的阻塞式写法,保证handler不会被长时间占用。 - 监听客户端断开:通过
r.Context().Done()实时感知客户端连接关闭事件,及时退出循环,避免服务端goroutine泄漏。 - 严格遵循SSE格式:保持
data: 内容\n\n的标准格式,确保客户端EventSource能正确解析推送内容。 - 强制刷新缓冲区:每次发送数据后调用
f.Flush(),避免Go HTTP缓冲区积压数据,确保消息实时推送给客户端。
客户端验证调整
可修改客户端onmessage回调打印具体数据,确认推送间隔:
event.onmessage = (e) => { console.log("收到推送:", e.data); };
运行服务后,客户端控制台会每2秒打印一条带时间戳的数据,实现稳定的SSE推送效果。
内容的提问来源于stack exchange,提问作者yahya kamran
相关产品推荐
相关产品推荐

