Revel WebSocket需Nginx透传Upgrade头、路由显式声明WS关键字、action签名首/二参数为*websocket.Conn、用x/net/websocket、手动管理连接生命周期。

Revel 对 WebSocket 的支持是原生的,但实际用起来容易卡在路由注册、连接握手或反向代理这三步。直接暴露 Revel 的 WebSocket 服务到公网不可行,必须配合 Nginx 正确透传升级请求,否则浏览器会报 WebSocket connection to 'wss://...' failed: Error during WebSocket handshake。
WS 路由写法和 action 签名必须严格匹配
Revel 的 WebSocket 路由不是靠中间件或配置开启的,而是靠 WS 关键字显式声明。不写 WS,哪怕 action 接收 *websocket.Conn 也没用。
-
WS /app/feed Application.Feed是合法路由;GET /app/feed或POST /app/feed即使后面接了同一个 action,也完全不会触发 WebSocket 握手 - action 函数签名必须包含
*websocket.Conn参数,且它**必须是第一个或第二个参数**(第一个是可选的string用户标识,如user string),例如:func (c Application) Feed(ws *websocket.Conn)或func (c Application) Feed(user string, ws *websocket.Conn) - Revel 不自动解析 URL path 中的参数(比如
/feed/{id})并绑定到函数参数,你需要手动从c.Params.Get("id")提取,或改用正则路由WS /feed/{id} Application.Feed再加id int参数
go.net/websocket 包已废弃,需适配 x/net/websocket
Revel 旧文档里写的 code.google.com/p/go.net/websocket 在 Go 1.12+ 已彻底失效,现在必须用 golang.org/x/net/websocket。但 Revel 源码本身没更新,所以你得自己确保 import 和构建环境一致。
- 运行
go get golang.org/x/net/websocket,确认包被拉到$GOPATH/src/golang.org/x/net/websocket/ - action 文件中 import 必须写成:
import "golang.org/x/net/websocket",不能用旧路径,否则编译失败 - 如果用的是较新 Revel fork(如 github.com/revel/revel v1.0+),部分版本已默认切换,但老项目迁移时极易漏掉这个 import 替换
Nginx 反向代理必须显式透传 Upgrade 请求头
Revel 应用监听 127.0.0.1:8089 时,Nginx 是唯一能正确处理 WebSocket 升级的前置组件。漏掉任意一个关键 header,连接就会卡在 101 Switching Protocols 之前。
- location 块里必须有这三行:
proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" -
$http_upgrade是 Nginx 内置变量,大小写敏感,写成$HTTP_UPGRADE或http_upgrade都无效 - 如果前端用
wss://,Nginx 还得配置 SSL 终止,并确保proxy_set_header X-Forwarded-Proto https,否则 Revel 的 request.URL.Scheme 可能仍是http,影响某些鉴权逻辑
Revel 的 WebSocket 连接生命周期需自行管理
Revel 不提供连接池、心跳、广播或断连回调——它只帮你拿到一个裸的 *websocket.Conn。所有读写、超时、重连、状态同步都得你自己写。
- 不要在 action 函数里直接 return,否则连接立即关闭;必须阻塞住 goroutine,例如用
for { ... websocket.Message.Receive(...) ... } - 务必设置读写超时:
ws.SetDeadline(time.Now().Add(30 * time.Second)),否则空闲连接会一直占着 fd - 没有内置广播机制,想群发就得自己维护一个
map[*websocket.Conn]bool,并在onOpen/onClose手动增删,注意并发安全(加sync.RWMutex)


















