revel框架本身不内置websocket支持,需手动集成gorilla/websocket等第三方库,在app.init()阶段用原生http.handle()注册websocket路径(如/api/ws),并配置nginx透传upgrade和connection头,实现与revel双轨共存。

Revel 框架本身不内置 WebSocket 支持,它的 HTTP 服务器基于 net/http,而标准库不提供 WebSocket 协议升级能力。想在 Revel 应用里实现 WebSocket 实时双向通信,必须手动集成第三方 WebSocket 库(如 gorilla/websocket),并绕过 Revel 的路由中间件体系直接接管连接升级逻辑。
gorilla/websocket 必须绕过 Revel 路由注册
Revel 的 routes 文件和控制器机制只处理普通 HTTP 请求,无法拦截并升级为 WebSocket 连接。WebSocket 握手需要底层 http.ResponseWriter 和 *http.Request 直接调用 Upgrader.Upgrade(),而 Revel 的 Controller.Render() 或 Result 会提前写响应头、关闭连接,导致升级失败。
- 必须在
app.Init()阶段(或app.Run()前)用原生http.Handle()注册 WebSocket 路径 - 示例路径不能是
/ws这类被 Revel 路由捕获的路径;推荐用显式前缀如/api/ws,并在routes中排除该路径(加GET /api/ws * 404防误入) -
Upgrader实例需提前声明,避免并发升级时复用问题
Upgrader 配置不兼容 Revel 默认 Header 处理
Nginx 反向代理环境下,若未正确透传 Upgrade 和 Connection 头,gorilla/websocket 会静默拒绝连接,浏览器报错 WebSocket connection to '...' failed: Error during WebSocket handshake。
- 必须在 Nginx 配置中显式启用 WebSocket 支持:
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
-
Upgrader.CheckOrigin默认拒绝非同源请求,开发时可临时设为func(r *http.Request) bool { return true },生产环境必须校验r.Header.Get("Origin") - 不要依赖 Revel 的
Request.RemoteAddr获取真实 IP:反向代理后它只是127.0.0.1,应读X-Real-IP或X-Forwarded-For
连接生命周期必须独立于 Revel Controller 实例
Revel 的每个请求都会新建一个 Controller 实例,但 WebSocket 连接一旦建立,就会长期存在,与任何单次 HTTP 请求无绑定关系。若把连接对象存进 c(*revel.Controller),连接会在请求结束时被 GC,导致消息发送 panic。
- 所有连接管理(
map[uint64]*websocket.Conn)、广播逻辑、心跳检测必须放在全局变量或单例 service 中 - 使用
sync.Map替代普通map,避免并发读写 panic - 关闭连接时务必调用
conn.Close(),否则 goroutine 泄漏;建议用defer包裹,并监听conn.ReadMessage()返回的io.EOF或websocket.CloseMessage
关键点不在“怎么写个 WebSocket 路由”,而在于“怎么让 Revel 和原生 net/http 共存而不互相干扰”。很多踩坑都源于试图把 Upgrader 塞进 Controller 方法里,或者忽略 Nginx 层对 WebSocket 头的透传要求。真正稳定运行的 Revel + WebSocket 服务,本质是「Revel 负责页面和 API,http.ServeMux 负责 WebSocket」的双轨结构。











