Golang Server Sent Events 服务端处理函数是否会持续自动调用?
问题解答
你观察到的/sse/dashboard路由处理函数反复被调用,并不是服务端主动自调用,而是浏览器EventSource的自动重连机制触发的,本质是客户端在反复发起新请求,和你理解的SSE服务端主动推送逻辑不符,问题出在你的服务端实现不符合SSE的规范要求:
- 你当前的服务端处理函数在返回1次counter数据后就直接结束执行,HTTP连接也随之断开
- 浏览器的EventSource对象默认检测到SSE连接断开后,会间隔3秒左右自动重新向目标接口发起请求,这才是你看到处理函数反复被触发的原因
SSE要求服务端保持长连接不中断,你需要在处理函数中阻塞住,持续向响应流中写入推送数据,而不是执行完就返回。Go语言中需要借助http.Flusher接口将缓冲区的数据实时推给客户端,修正后的服务端代码如下:
package main import ( "fmt" "log" "net/http" "time" ) var counter int func main() { http.Handle("/", http.FileServer(http.Dir("client"))) http.Handle("/sse/dashboard", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "Streaming unsupported", http.StatusInternalServerError) return } // 监听客户端断开连接的信号 notify := r.Context().Done() for { select { case <-notify: // 客户端断开连接,退出循环结束处理函数 return default: counter++ fmt.Fprintf(w, "data: %v\n\n", counter) // 主动刷新缓冲区,把数据立即推给客户端 flusher.Flush() time.Sleep(time.Second) } } })) log.Fatal(http.ListenAndServe(":8080", nil)) }
修正后服务端会在同一个TCP长连接里每秒主动推送一次新的counter值,处理函数只会在客户端连接建立时被调用1次,后续推送都在同一个连接内完成,不会再出现反复触发路由处理函数的情况,这才是SSE真正的服务端主动推送模式。
内容的提问来源于stack exchange,提问作者Bryan
相关产品推荐
相关产品推荐

