应使用 github.com/gofiber/contrib/websocket 而非手写升级逻辑,因 Fiber 不内置 WebSocket 实现;c.IsWebSocket() 仅校验握手头,不处理帧读写、心跳、并发等,需手动升级且易出错;websocket.New() 自动完成升级并注入 *websocket.Conn,但需注意 CheckOrigin 默认拒绝跨域、HandshakeTimeout 和 MaxMessageSize 等配置陷阱。

直接用 github.com/gofiber/contrib/websocket 包,别自己手写升级逻辑 —— Fiber 原生不内置 WebSocket 服务端实现,contrib/websocket 才是官方推荐、稳定可用的方案。
为什么不能直接用 c.IsWebSocket() 建立连接
c.IsWebSocket() 只是个握手检测工具,它只做四件事:检查 Connection: upgrade、Upgrade: websocket、Sec-WebSocket-Key 是否存在、Sec-WebSocket-Version 是否为 13。它不处理后续帧读写、连接保持、心跳或并发管理。
- 调用
c.IsWebSocket()返回true后,你仍需手动调用c.Fasthttp.Upgrade(),再自己解析帧、维护连接状态 —— 这极易出错且无必要 - Fiber 的
ctx生命周期绑定 HTTP 请求,WebSocket 连接一旦升级,就脱离了该生命周期,继续用c操作会 panic 或静默失败 - 真实项目中需要处理 ping/pong、连接超时、并发读写竞争、close 码透传等,这些
IsWebSocket()完全不提供
websocket.New() 的实际用法和参数陷阱
websocket.New() 是 contrib/websocket 提供的封装,它自动完成升级、创建 *websocket.Conn,并把控制权交给你的 handler 函数。关键点在初始化参数:
-
CheckOrigin默认为nil,即拒绝所有跨域请求 —— 开发时若前端跑在localhost:5173,必须显式设为func(r *http.Request) bool { return true },否则握手直接 403 -
HandshakeTimeout默认 45 秒,但某些代理(如 Nginx)可能提前断连,建议设为10 * time.Second -
MaxMessageSize默认 1MB,若业务要传大文件或日志流,需提前调大,否则ReadMessage()报websocket: close 1009 (message too big)
示例片段:
<pre class="brush:php;toolbar:false;">app.Get("/ws", websocket.New(func(c *websocket.Conn) {
// 此处 c 已是完整 WebSocket 连接,可安全读写
for {
mt, msg, err := c.ReadMessage()
if err != nil {
log.Println("read error:", err)
return
}
if err = c.WriteMessage(mt, msg); err != nil {
log.Println("write error:", err)
return
}
}
}, websocket.Config{
CheckOrigin: func(r *http.Request) bool { return true },
HandshakeTimeout: 10 * time.Second,
}))
客户端消息类型(mt)与服务端响应逻辑
ReadMessage() 返回的第一个值 mt 是操作码(opcode),它决定了数据性质和后续处理方式:
-
websocket.TextMessage:payload 是 UTF-8 字符串,适合聊天、指令类文本;若误用WriteMessage(websocket.BinaryMessage, ...)回传,浏览器onmessage会收到Blob而非string -
websocket.BinaryMessage:payload 是[]byte,适合传输 protobuf、图片切片等;服务端必须用同类型回写,否则客户端解析失败 -
websocket.PingMessage/PongMessage:底层自动响应,无需手动处理;但若你在循环里阻塞太久(比如数据库查询 > 30s),可能导致心跳超时断连 - 收到
websocket.CloseMessage时,应立即return退出循环,避免后续WriteMessage()panic
真正容易被忽略的是连接生命周期管理:Fiber 的 websocket.Conn 不自动注册到任何连接池,所有连接都靠你自行维护 map + mutex。如果要做广播或房间管理,sync.Map 存 *websocket.Conn 是起点,但记得在 defer 或 recover() 中清理 —— 否则内存泄漏比想象中来得快。


















