Revel框架中WebSocket路由需在conf/routes文件显式声明,格式为“WS /path Controller.Action”,Handler函数必须接收*websocket.Conn参数且不返回revel.Result,收发消息须用websocket.Message.Send/Recv,连接生命周期需手动管理。

Revel框架里怎么注册WebSocket路由
Revel不走Spring Boot那种注解自动扫描路线,必须显式在routes文件里声明WebSocket端点。漏写这一步,请求直接404,连握手都进不来。
你得加一行类似这样的配置:
WS /ws/feed Application.Feed
注意三点:WS是关键字,不能写成GET或POST;路径必须以/ws/这类前缀开头(虽然不是强制,但避免和REST路由冲突);Application.Feed要和实际Controller方法签名完全匹配。
常见错误:把WS写成小写ws,或者路径写成/feed却没在HTTP路由里排除它,结果Revel优先匹配了GET /feed导致协议升级失败,浏览器控制台报Unexpected response code: 200。
Handler函数必须接收*websocket.Conn参数
Revel的WebSocket handler不是普通HTTP action,它不返回revel.Result,而是直接操作底层连接对象。函数签名必须严格满足:
func (c App) Feed(ws *websocket.Conn) { ... }别试图加user string、id int64之类的额外参数——Revel不会帮你解析URL路径参数传进来,这些得你自己从ws.Request().URL.Query()里取,或者提前在HTTP中间件里做鉴权并存到c.Session中。
容易踩的坑:
- 忘记import "code.google.com/p/go.net/websocket",编译报undefined: websocket
- 把*websocket.Conn错写成websocket.Conn(少个*),Go类型检查直接拒绝
- 在handler里调用c.RenderJSON()之类的方法,会panic:「cannot render in websocket handler」
消息收发要用websocket.Message.Send/Recv,别碰Conn.Write/Read
Revel封装的*websocket.Conn是net/http标准库的扩展,但它的Write和Read方法不处理WebSocket帧格式。直接调用会导致客户端收到乱码或连接被服务器强制关闭。
正确做法是用websocket.Message包提供的工具函数:
-
websocket.Message.Send(ws, data)发送任意可序列化结构体或字符串 -
websocket.Message.Recv(ws, &target)接收并反序列化到变量
例如:
type ChatMsg struct { From string `json:"from"` Text string `json:"text"` }<br>var msg ChatMsg<br>err := websocket.Message.Recv(ws, &msg)性能提示:频繁发送小消息时,Send/Recv内部有缓冲优化;如果自己用Conn.Write拼帧,反而容易触发TCP小包问题,增加延迟。
连接生命周期管理得自己兜底
Revel不提供@OnOpen/@OnClose这类钩子,所有连接状态维护全靠你在handler里手动处理。最常被忽略的是异常退出场景:
客户端关浏览器、网络中断、心跳超时——这些都会让ws.Read或ws.Write返回error,但如果你没检查err就继续读写,程序会panic或goroutine泄漏。
务必在循环收发逻辑里加判断:
for {<br> var msg string<br> if err := websocket.Message.Recv(ws, &msg); err != nil {<br> // 连接已断,清理资源,return<br> log.Printf("WS recv error: %v", err)<br> return<br> }<br> // 处理消息...<br>}复杂点在于:Revel没有内置会话池,你要存活跃连接,得自己用sync.Map或Redis,且记得在defer里删掉map里的key——否则内存只增不减。

















