应选用melody而非标准net/http,因其基于gorilla/websocket封装,内置连接管理、广播、心跳及断线重连等能力,解决原生方案的并发写锁、连接泄漏和广播性能差等问题。

为什么不用标准 net/http 而选 Melody
Melody 是基于 gorilla/websocket 封装的轻量级 WebSocket 服务库,它把连接管理、广播、心跳、断线重连这些重复逻辑都收拢了。如果你用原生 net/http + gorilla/websocket 手搓推送,很快会卡在并发写锁、连接泄漏、广播性能差这些问题上——比如 conn.WriteMessage() 不是并发安全的,而 Melody 内部用 channel + goroutine 做了写队列,天然支持高并发推送。
初始化 Melody 实例并挂载到 HTTP 路由
别直接用 melody.New() 后裸奔,得配好心跳和超时,否则客户端假死连接会越积越多:
import "github.com/olahol/melody"
<p>m := melody.New()
m.Config.MaxBufferSize = 1024 <em> 1024 // 防大消息爆内存
m.Config.ReadTimeout = 30 </em> time.Second
m.Config.WriteTimeout = 30 <em> time.Second
m.Config.PingPeriod = 10 </em> time.Second // 心跳间隔
m.Config.PongWait = 30 * time.Second</p><p>// 挂到 Gin(或其他框架)路由下
r.Get("/ws", func(c *gin.Context) {
m.HandleRequest(c.Writer, c.Request)
})
</p>
- 必须显式设置
PingPeriod和PongWait,否则默认值会导致部分浏览器客户端误判断连 -
MaxBufferSize不设的话,恶意客户端发超长消息会 OOM - 不要在
HandleRequest外再调用Upgrade,Melody 已内部处理
推送消息时避免阻塞主线程
Melody 的 session.Write() 是同步阻塞的,如果对上千连接逐个调用,会卡住整个服务。正确做法是用 m.Broadcast() 或 m.BroadcastFilter():
// 推送给所有人(推荐)
m.Broadcast([]byte(`{"event":"update","data":123}`))
<p>// 推送给指定用户(需提前在 session.Set() 存 ID)
m.BroadcastFilter(func(s *melody.Session) bool {
uid, ok := s.Get("uid").(string)
return ok && uid == "user_123"
}, []byte(<code>{"msg":"private"}</code>))
</p>
-
session.Write()只适合单点调试或极低频场景,线上严禁循环调用 -
Broadcast()底层是并发写,但消息体太大(>64KB)会影响吞吐,建议拆成小包 - 如果要用
session.Write(),务必套select+timeout,防止某个坏连接拖垮全局
连接生命周期里必须清理 session 状态
Melody 不自动帮你存业务状态(比如用户 ID、房间号),全靠你在 OnConnect 里 session.Set(),但更关键的是:断连时必须主动清理,否则内存泄漏比连接数涨得还快:
m.HandleConnect(func(s *melody.Session) {
s.Set("uid", getUIDFromToken(s.Request.URL.Query().Get("token")))
})
<p>m.HandleDisconnect(func(s *melody.Session) {
if uid, ok := s.Get("uid").(string); ok {
// 清理 Redis 在线状态、移出房间列表等
redisClient.Del(ctx, "online:"+uid)
removeUserFromRoom(uid, getCurrentRoom(s))
}
})
</p>
-
HandleDisconnect不保证 100% 触发(比如客户端硬断电),所以业务层还得配定时扫描+心跳超时兜底 - 别在
OnConnect里做耗时操作(如查 DB),会阻塞新连接接入;异步加载后用s.Set()即可 - 所有
s.Get()返回值都要类型断言,Melody 不做类型检查,错类型会导致 panic
真正难的不是接上 WebSocket,而是让每个连接活够生命周期、不带状态残留地退出。Melody 把底层跑通了,剩下的业务状态一致性,得你一处处对齐。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











