You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:36:06