如何解决gofiber/websocket下WebSocket断开连接状态码1006的问题
gofiber/websocket/v2 频繁返回1006状态码的解决办法
WebSocket的1006状态码代表连接异常中断,两端没有收到正常的关闭帧,针对你已经配置了ping-pong仍出现该问题的场景,按以下步骤排查即可:
1. 修正心跳与超时配置逻辑
gofiber/websocket基于gorilla/websocket封装,默认未开启读写超时,且需要显式绑定pong处理逻辑重置超时,正确配置示例如下:
// 路由中间件 app.Use("/ws", func(c *fiber.Ctx) error { if websocket.IsWebSocketUpgrade(c) { return c.Next() } return fiber.ErrUpgradeRequired }) // WebSocket处理逻辑 app.Get("/ws", websocket.New(func(conn *websocket.Conn) { // 初始化读超时为60s conn.SetReadDeadline(time.Now().Add(60 * time.Second)) // 收到pong帧时重置读超时 conn.SetPongHandler(func(appData string) error { conn.SetReadDeadline(time.Now().Add(60 * time.Second)) return nil }) // 启动ping发送协程,间隔25s(必须小于读超时的60s,建议为读超时的1/2到2/3) go func() { ticker := time.NewTicker(25 * time.Second) defer ticker.Stop() for range ticker.C { if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil { // 发送失败直接退出,关闭连接 return } } }() // 你的业务读循环 for { msgType, msg, err := conn.ReadMessage() if err != nil { break } // 业务逻辑处理 } }, websocket.Config{ HandshakeTimeout: 10 * time.Second, // 读写缓冲区根据业务单条消息最大值调整,避免过小导致拆包断连 ReadBufferSize: 4096, WriteBufferSize: 4096, }))
2. 排查客户端响应逻辑
- 若使用非浏览器原生的第三方WebSocket客户端,需确认客户端已配置自动响应ping帧,或手动实现pong帧返回逻辑,未响应ping会导致服务端超时主动断连
- 浏览器原生WebSocket会自动响应ping帧,无需额外处理
3. 规避业务逻辑阻塞
不要在WebSocket的读循环内执行耗时操作(同步查库、调用第三方接口等),这类操作会阻塞pong handler的触发,导致读超时到期触发断连,所有耗时逻辑需放到独立协程异步处理。
4. 适配中间代理的超时规则
- 大部分Nginx、CDN、负载均衡默认的WebSocket空闲连接超时为30-60s,若你的ping间隔大于该阈值,中间节点会主动切断空闲连接,需将ping间隔调整为15-30s,小于中间节点的超时阈值
- 若使用Nginx反向代理,需添加以下配置:
location /ws { proxy_pass http://你的后端服务地址; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; # 代理超时需大于服务端设置的读超时,这里设为120s proxy_read_timeout 120s; proxy_send_timeout 120s; }
5. 修复并发写问题
gorilla/websocket的写方法不是并发安全的,多个协程同时往同一个连接写消息会导致连接异常断开,需通过加锁或者单独发送协程的方式控制写操作:
// 示例:用channel统一管控写操作 app.Get("/ws", websocket.New(func(conn *websocket.Conn) { sendCh := make(chan []byte, 64) // 单独的写协程 go func() { for msg := range sendCh { if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil { return } } }() // 业务侧要发消息直接写入sendCh即可,不要直接调用WriteMessage }))
内容的提问来源于stack exchange,提问作者Swathi K
相关产品推荐
相关产品推荐

