Gin不原生支持WebSocket,需在/ws路由中调用gorilla/websocket.Upgrader.Upgrade()完成协议切换;升级后必须通过*websocket.Conn收发消息,禁用gin.Context相关方法;生产环境须严格校验Origin头;连接管理需自行实现Hub。

直接注册 /ws 路由并传入升级函数即可
Gin 本身不处理 WebSocket 协议,它只负责把 HTTP 请求交给 gorilla/websocket.Upgrader.Upgrade() 去做协议切换。所以你不需要“配置 WebSocket”,只需要在某个路由(比如 GET /ws)里调用升级逻辑,并确保后续操作完全脱离 *gin.Context。
常见错误是试图在升级后继续用 c.JSON() 或 c.Writer.Write() 发送数据——这会 panic 或静默失败,因为 HTTP 响应头已经写出,连接已被接管。
-
upgrader.Upgrade(c.Writer, c.Request, nil)必须在路由 handler 内同步调用,不能 defer - 升级成功后立刻
defer conn.Close(),否则连接泄漏 - 不要在 handler 返回前启动 goroutine 处理消息——必须确保
conn已建立且未关闭 - 生产环境务必重写
CheckOrigin,禁止return true
Upgrader 的 CheckOrigin 不设白名单等于裸奔
几乎所有入门示例都写 CheckOrigin: func(r *http.Request) bool { return true },这是开发阶段的权宜之计。上线后,任何域名都能发起 WebSocket 连接,攻击者可借此打满你的连接数或伪造身份。
正确做法是提取 Origin 头,比对预设域名列表:
CheckOrigin: func(r *http.Request) bool {
origin := r.Header.Get("Origin")
for _, allowed := range []string{"https://your-app.com", "https://admin.your-app.com"} {
if origin == allowed {
return true
}
}
return false
}
注意:如果前端走的是 file:// 或本地 localhost:8080,也要显式加入白名单,否则连不上。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
为什么不能在 gin.Context 里读写消息
*gin.Context 生命周期绑定 HTTP 请求,一旦 Upgrade() 成功,底层 TCP 连接就脱离了 HTTP 模型。此时 c 对象里的 Writer、Request 等字段已失效,再调用 c.Abort() 或 c.Next() 没有意义,c.Writer.Write() 会直接 panic。
所有消息收发必须通过原生 *websocket.Conn 对象:
- 用
conn.ReadMessage()替代任何基于c的读取 - 用
conn.WriteMessage()替代c.String()或c.Data() - 心跳(ping/pong)也得自己处理:
conn.SetPingHandler(...)和conn.SetPongHandler(...)
多个连接管理必须自己实现 Hub,Gin 不提供
Gin 没有内置连接池、广播机制或客户端状态管理。你要支持群聊、私信、在线列表等功能,就得手写 Hub 结构体——它通常包含:map[*websocket.Conn]bool 存活连接、chan 接收注册/注销/广播事件、一个长期运行的 for-select 循环驱动状态变更。
最容易被忽略的是:每个 *websocket.Conn 必须配一个独立的 send channel,并在 writer goroutine 中消费它。否则并发写会 panic;而 channel 缓冲区大小(如 make(chan []byte, 256))决定了消息积压上限,太小容易丢消息,太大吃内存。


















