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

Bun环境下Discord网关WebSocket偶发消息接收异常问题

排查Bun环境下Discord网关WebSocket连接不稳定问题

核心问题分析

你的代码在Node.js正常但Bun下时好时坏,主要是因为Bun与Node.js在WebSocket实现细节、消息处理方式上存在差异,加上代码中存在的几个通用问题导致的。

具体修复方案

1. 处理WebSocket消息的类型差异

Bun中WebSocket的message事件参数可能是ArrayBuffer/Blob而非字符串,直接JSON.parse(e)会抛出错误,导致后续代码终止执行(无输出的情况大概率是这个原因)。需要先将消息转换为字符串:

ws.on("message", async (e) => {
  // 统一将消息转为字符串
  const data = typeof e === 'string' ? e : await new Response(e).text();
  const p = JSON.parse(data);
  const { t, d, op, s } = p;
  
  // ... 后续逻辑
});

2. 修正心跳包的sequence number

Discord网关要求心跳包(op=1)的d值必须是最近收到的事件序列号(s字段),而非固定的251。固定值会导致网关判定连接无效,随机断开:

let lastSequence = null;

ws.on("message", async (e) => {
  // ... 解析数据
  lastSequence = s ?? lastSequence; // 更新最近的序列号
  
  if (op == 10) {
    ping(d.heartbeat_interval);
    console.log("interval started");
    ws.send(JSON.stringify(payload));
  }
  
  // ...
});

function ping(ms) {
  return setInterval(() => {
    // 使用最近的序列号发送心跳
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ op: 1, d: lastSequence }));
    }
  }, ms);
}

3. 添加错误与关闭事件监听

原代码没有错误处理,无法排查连接失败、发送失败的原因,加上监听可以定位问题:

ws.on("error", (err) => {
  console.error("WebSocket错误:", err);
});

ws.on("close", (code, reason) => {
  console.log("连接关闭:", code, reason.toString());
});

4. 确保发送时机的可靠性

在发送身份验证 payload 前,确认WebSocket处于OPEN状态,同时可以处理send的返回值(Bun中send返回Promise):

if (op == 10) {
  ping(d.heartbeat_interval);
  console.log("interval started");
  if (ws.readyState === WebSocket.OPEN) {
    try {
      await ws.send(JSON.stringify(payload));
      console.log("身份验证payload已发送");
    } catch (err) {
      console.error("发送payload失败:", err);
    }
  }
}

完整修改后的代码

const ws = new WebSocket("wss://gateway.discord.gg/?v=10&encoding=json");
const TOKEN = "你的令牌"; // 替换为实际令牌

const payload = {
  op: 2,
  d: {
    token: TOKEN,
    intents: 513,
    properties: {
      os: "linux",
      browser: "chrome",
      device: "chrome",
    },
  },
};

let lastSequence = null;
let heartbeatInterval = null;

ws.on("open", () => {
  console.log("连接已打开");
});

ws.on("error", (err) => {
  console.error("WebSocket错误:", err);
});

ws.on("close", (code, reason) => {
  console.log("连接关闭:", code, reason.toString());
  if (heartbeatInterval) clearInterval(heartbeatInterval);
});

ws.on("message", async (e) => {
  try {
    const data = typeof e === 'string' ? e : await new Response(e).text();
    const p = JSON.parse(data);
    const { t, d, op, s } = p;
    
    lastSequence = s ?? lastSequence;
    
    console.log(`收到op: ${op}, 事件: ${t}`);
    
    if (op === 10) {
      heartbeatInterval = ping(d.heartbeat_interval);
      console.log("心跳定时器已启动");
      if (ws.readyState === WebSocket.OPEN) {
        await ws.send(JSON.stringify(payload));
        console.log("身份验证请求已发送");
      }
    } else if (op === 1) {
      // 响应网关的心跳请求
      if (ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({ op: 1, d: lastSequence }));
      }
    }
  } catch (err) {
    console.error("消息处理失败:", err);
  }
});

function ping(ms) {
  return setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ op: 1, d: lastSequence }));
      console.log("发送心跳包");
    }
  }, ms);
}

额外注意事项

  • Bun的WebSocket实现目前仍在迭代,部分细节与Node.js的ws库有差异,建议关注Bun官方文档的WebSocket相关更新
  • 确保你的Discord令牌权限正确,intents设置符合需求(513对应GUILDS和GUILD_MESSAGES)

内容的提问来源于stack exchange,提问作者clapmemereview

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:31:06