Iris v12 内置 websocket 包不兼容 RFC 6455,因绕过标准 Upgrade 握手、缺失 Upgrade: websocket 和 Sec-WebSocket-Accept 响应头,导致浏览器 new WebSocket() 握手失败;必须用 gorilla/websocket 手动升级或改用 go-socket.io。

Iris 本身不提供符合 RFC 6455 的标准 WebSocket 支持,直接用 websocket 包注册路由会握手失败——浏览器控制台报 WebSocket connection to 'ws://' failed 或 net::ERR_CONNECTION_RESET,Nginx 日志显示 upstream sent no valid HTTP/1.0 header。必须手动接管 Upgrade 流程,或换用兼容 Socket.IO 协议的方案。
用 gorilla/websocket 手动升级 WebSocket 连接
这是最可控、最贴近原生 WebSocket 的方式,适用于需要自定义帧处理、对接 uni-app uni.connectSocket 或已有二进制协议的场景。
- 路由必须用
app.Any("/ws", wsHandler),不能用Get—— 因为后续 ping/pong/text/binary 帧不是 HTTP 方法,Any才能兜住全部 -
upgrader.Upgrade(w, r, nil)第三个参数传nil,否则 Nginx 等代理可能拦截Sec-WebSocket-Extensions导致 400 - 升级后拿到的
*websocket.Conn不属于Context生命周期,ctx.ResponseWriter()已失效,不能再调用ctx.WriteString或fmt.Fprint - 务必设置读写超时:
conn.SetReadDeadline防僵死连接;用conn.WriteMessage发送,别用 HTTP 写法 - 生产环境必须实现
CheckOrigin,例如:CheckOrigin: func(r *http.Request) bool { return r.Header.Get("Origin") == "https://yourdomain.com" }
用 go-socket.io 实现带命名空间和房间的实时通信
如果你需要事件广播、房间隔离、自动降级(WebSocket 不可用时 fallback 到长轮询),go-socket.io 是更稳妥的选择,它与 Iris 兼容良好,且协议层对前端更友好。
- 初始化后,用
app.HandleMany挂载路由:app.HandleMany("GET,POST", "/socket.io/", func(ctx iris.Context) { server.ServeHTTP(ctx.ResponseWriter(), ctx.Request()) }) - 注意路径必须是
/socket.io/(结尾带斜杠),且需同时支持 GET 和 POST —— Socket.IO 客户端初始化时会先发 OPTIONS/GET,后续心跳和消息走 POST -
server.OnConnect中获取的socketio.Conn是独立生命周期对象,断开后需自行清理状态(如从房间移除) - 广播到房间用
s.Emit("message", data)或server.BroadcastToRoom("/", "room1", "message", data),命名空间(第一个参数)通常填"/" - 不要在
OnConnect里阻塞操作,比如同步 DB 查询,建议起 goroutine 或用 channel 异步处理
为什么 Iris 自带 websocket 包不能直接用
它的 github.com/kataras/iris/v12/websocket 是个内存级连接管理器,绕过了标准 Upgrade 握手流程:响应头缺失 Upgrade: websocket 和正确计算的 Sec-WebSocket-Accept,浏览器直接拒绝连接。
- 即使你在路由里写了
app.Get("/ws", websocket.Handler(...)),前端new WebSocket("ws://.../ws")仍会失败 - 该模块适合内部服务间轻量长连接(如 metrics 推送),但不适用于浏览器直连
- 它不处理 ping/pong 帧,也不兼容任何代理(Nginx、CDN、Cloudflare)的 WebSocket 支持逻辑
- 错误日志往往静默,只在浏览器控制台或代理层暴露问题,排查时容易误判为网络或 CORS 问题
真正落地时,80% 的需求其实更适合 go-socket.io:它省去了手动维护连接状态、心跳、重连、降级的复杂度;而剩下 20% 对性能或协议有强定制要求的场景,才值得投入精力用 gorilla/websocket 从头搭。别被 “Iris 自带 websocket” 这个名字误导——它不是你想要的那个 WebSocket。











