生产环境稳定推送服务需三要素:选对协议(websocket/sse/http)、解耦触发与发送、严格管理连接生命周期;须校验跨域、正确flush、并发安全广播、token刷新及异步重试。

直接上生产环境能跑通、不卡死、不丢消息的推送服务,核心就三件事:选对协议、解耦触发和发送、管住连接生命周期。别一上来就写 WebSocket,先想清楚你到底要单向通知还是双向交互。
WebSocket 推送卡在握手阶段?99% 是跨域或 URL 写错了
浏览器控制台报 Failed to execute 'send' on 'WebSocket': Still in CONNECTING state 或直接没反应,基本不是代码问题,而是握手失败。
- 前端必须用
ws://或wss://开头,写成http://浏览器根本不会发 Upgrade 请求 -
upgrader.CheckOrigin默认拒绝所有跨域请求;开发可临时设为func(r *http.Request) bool { return true },但上线前必须校验 Origin 头,比如return r.Header.Get("Origin") == "https://myapp.com" - 如果前端走 Nginx,确认它透传了
Origin头:proxy_set_header Origin $http_origin;
SSE 推送没收到?漏 flush 或客户端没设好 EventSource
服务端写了 fmt.Fprintf(w, "data: hello\n\n") 却没输出,常见于没调用 Flusher.Flush(),或者客户端用 fetch() 而不是 EventSource。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
- 必须先判断
flusher, ok := w.(http.Flusher),再调flusher.Flush();io.Copy()或json.NewEncoder().Encode()不会触发 flush - 响应头缺一不可:
Content-Type: text/event-stream、Cache-Control: no-cache、Connection: keep-alive - 客户端必须用
new EventSource("/sse"),不是fetch();且要监听message事件,不是response.text()
HTTP Handler 里遍历写 WebSocket 连接?立刻停手
在 HTTP 接口里直接对 *websocket.Conn 调 WriteMessage(),轻则 panic,重则整个连接池卡死——因为 *websocket.Conn 不是并发安全的。
- 所有推送必须走一个带缓冲的广播 channel:
broadcast := make(chan []byte, 100) - 单独起一个 goroutine 持续读这个 channel,并遍历 clients map 分发,每个 client 写操作串行执行
- clients map 必须用
sync.RWMutex保护读写,注册/注销走独立 channel,避免直接操作 map
FCM / 企微 / 钉钉推送总失败?别裸写 Send(),先管 token 和重试
调 fcmClient.Send() 返回 message ID 不代表设备收到了;调 wechat.Send() 报 429 更不是网络问题,而是频控触发了。
- access_token 必须带刷新逻辑,不能 New 一次就全局缓存;用
sync.RWMutex包裹字段,或直接存 Redis 并设 TTL - Send() 出错时,检查 error 类型:
messaging.Unregistered要删 token,http.StatusTooManyRequests要延迟重试(比如time.AfterFunc(30*time.Second, func(){...})) - 别在 handler 里同步等 Send() 返回;go 异步发 + channel 控制并发数(如最多 5 个 worker),避免打爆上游限流
真正难的从来不是连上 WebSocket 或发一条 FCM,而是当 1000 个连接同时在线、每秒 50 条消息涌进来时,广播不卡、token 不过期、重试不堆栈、离线消息不丢——这些细节藏在 flush 的时机、channel 的缓冲大小、mutex 的粒度里,而不是文档第一行写的那句 “import github.com/gorilla/websocket”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










