beego 本身不内置 websocket 实现,必须依赖 gorilla/websocket 手动集成;其 controller 无握手逻辑,仅能路由到 http handler 后由开发者调用 upgrade 完成协议升级,且需显式配置 checkorigin、缓冲区大小和超时以避免跨域失败、写超时及 goroutine 泄漏。

Beego 本身不内置 WebSocket 实现,必须依赖 github.com/gorilla/websocket 手动集成——这是所有 Beego WebSocket 开发绕不开的第一步,也是最容易卡住的地方。
为什么不能直接用 beego.Controller 的原生方法?
Beego 的 Controller 没有封装 WebSocket 协议握手逻辑;它只处理 HTTP 请求生命周期。所谓“Beego 支持 WebSocket”,实际是指它能路由到一个普通 HTTP handler,再由你用 gorilla/websocket 手动升级连接。官方文档里没有 this.WebSocket() 这样的方法,强行调用会编译失败或 panic。
- Beego 路由仍走
beego.Router("/ws", &controllers.WsController{}),但控制器里不能调用this.ServeJSON()或this.Render() -
Get()方法必须手动调用upgrader.Upgrade(),且需在响应头写出前完成(否则 HTTP 状态码已发,无法升级) - 一旦升级成功,
this.Ctx.ResponseWriter和this.Ctx.Request就不能再用于其他 HTTP 操作
upgrader 配置的三个关键点
默认的 websocket.Upgrader 在生产环境几乎一定会出问题,尤其遇到 Nginx 反向代理时。必须显式配置以下三项:
-
CheckOrigin: func(r *http.Request) bool { return true }—— 否则跨域请求直接被拒绝(前端连不上) -
ReadBufferSize和WriteBufferSize建议设为4096或更高(小包频繁时默认 1024 容易触发websocket: write deadline exceeded) -
HandshakeTimeout必须设(如10 * time.Second),否则客户端超时后重连,服务端 goroutine 泄漏
错误写法:var upgrader = websocket.Upgrader{};正确写法应包含上述三项显式设置。
goroutine 泄漏和连接关闭的常见陷阱
每个 WebSocket 连接对应一个 goroutine,但很多人忘了:连接断开时,必须显式关闭 *websocket.Conn、清空引用、退出读/写循环——否则 goroutine 永远挂起,内存持续增长。
- 读循环中用
ws.ReadMessage(),必须检查err == io.EOF || websocket.IsCloseError(err, websocket.CloseAbnormalClosure),然后ws.Close() - 写循环中不能直接
ws.WriteMessage(),要加select+default防阻塞,否则广播消息时某个 client 卡住会导致整个 loop hang 住 - 不要在
defer ws.Close()里做清理——defer只在函数返回时执行,而 WebSocket handler 通常是个长运行的for循环,defer根本不会触发
Nginx 反向代理必须配的三行
如果你跳过这步,前端 WebSocket 连接大概率会卡在 pending 状态,或者几秒后自动断开。Beego 应用跑在 8080,Nginx 做反代时,nginx.conf 至少要加:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream backend {
server 127.0.0.1:8080;
}
server {
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 86400; # 关键:不能用默认 60 秒
}
}
其中 proxy_read_timeout 必须设为大值(如一天),否则 Nginx 会在无数据时主动断连,而 Beego 并不知道,连接状态滞留。
最常被忽略的其实是心跳机制:Beego 不帮你管连接存活,gorilla/websocket 也不自动发 ping。如果客户端网络波动或 NAT 超时,连接会静默失效——你得自己实现 ping/pong,且必须在 SetPingHandler 和 SetPongHandler 里重置读超时,否则一次 pong 延迟就导致整条连接被 kill。











