You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 02:54:04