WebSocket控制器必须嵌入neffos.Struct并实现OnConnect等钩子,路径须为固定字符串、不可带参数,依赖注入不支持iris.Context相关类型,生产环境需自定义CheckOrigin和超时。

WebSocket控制器必须实现 neffos.Struct 接口
Iris 的 MVC WebSocket 不是直接用 websocket.Upgrader 手动升级,而是通过 neffos(Iris 官方维护的 WebSocket 库)抽象为结构体控制器。你写的 struct 必须嵌入 neffos.Struct 或实现其方法,否则 HandleWebsocket 会静默失败或 panic。
-
neffos.Struct提供了OnConnect、OnDisconnect、OnError等钩子,不是可选——至少得空实现,否则运行时报panic: method OnConnect not found - 不要在 struct 里定义
func(ctx iris.Context)类型的方法;MVC WebSocket 控制器的方法签名是func(ns *neffos.NSConn, msg neffos.Message) error - 若需访问 Iris 的
Context(比如读取 query 或 header),得在OnConnect里从ns.Conn().Request()拿,不能传入 controller 方法
HandleWebsocket 路由路径不支持通配符和参数
你不能写 app.HandleWebsocket("/ws/{room:string}") —— 这会导致连接立即关闭,且无明确错误日志。Iris 的 WebSocket MVC 注册只接受固定路径字符串,如 /ws 或 /chat。
- 动态逻辑(如房间 ID、用户 token)必须放在 query 中,例如
ws://localhost:8080/ws?room=general&token=abc - 在
OnConnect回调里解析ns.Conn().Request().URL.Query()获取这些值,再决定是否允许连接或存入 session - 路径末尾加斜杠(如
/ws/)会导致浏览器 WebSocket 构造函数报InvalidStateError,服务端也收不到 upgrade 请求
依赖注入在 WebSocket controller 中受限
MVC 的 app.Register 注入的服务(如数据库、缓存)能进 WebSocket controller,但 iris.Context 相关对象(如 iris.Application、iris.Logger)不能直接注入——因为 WebSocket 生命周期脱离 HTTP 请求上下文。
- 可安全注入:自定义 service struct、
*sql.DB、redis.Client、函数类型依赖 - 不可注入:
iris.Context、iris.Application、任何带iris.Context方法接收者的类型 - 日志要改用全局 logger(如
app.Logger().Infof)或注入*zerolog.Logger实例,而不是依赖 context 绑定的 logger
生产环境必须重写 CheckOrigin 并设超时
默认的 websocket.Upgrader 允许任意来源,这在生产中等于裸奔。Iris 的 MVC WebSocket 底层仍走标准 Go net/http upgrade 流程,所以 origin 校验和连接超时必须显式控制。
- 在注册前设置全局 upgrader:
neffos.DefaultUpgrader.CheckOrigin = func(r *http.Request) bool { return r.Header.Get("Origin") == "https://myapp.com" } - 连接空闲超时默认是 0(永不超时),容易被恶意长连接拖垮。应设
neffos.DefaultUpgrader.HandshakeTimeout = 5 * time.Second - 消息读写超时也要设,否则一个卡死的客户端会阻塞整个 goroutine:
conn.SetReadDeadline(time.Now().Add(30 * time.Second))需在OnConnect后手动调用
实际最简可用结构体长这样:
type ChatController struct {
neffos.Struct
DB *sql.DB `inject:""`
}
<p>func (c <em>ChatController) OnConnect(ns </em>neffos.NSConn, msg neffos.Message) error {
// 解析 query
q := ns.Conn().Request().URL.Query()
room := q.Get("room")
if room == "" {
return errors.New("missing room")
}
// 写日志用全局 app logger,不是 ctx.Logger()
ns.Conn().Application().Logger().Infof("connected to %s", room)
return nil
}</p><p>func (c <em>ChatController) OnMessage(ns </em>neffos.NSConn, msg neffos.Message) error {
<em>, </em> = c.DB.Exec("INSERT INTO messages ...", msg.Body)
return ns.Emit("reply", []byte("ok"))
}真正麻烦的从来不是连上,而是怎么在断连重试、消息乱序、广播风暴、鉴权续期这些环节不出错——这些全得靠你在 OnConnect/OnDisconnect 和自定义 namespace 里手工兜底。


















