发送首次心跳后Discord API不再推送事件,该如何排查解决?
故障原因
- 首次心跳发送时机不符合Discord网关规范:Discord官方要求收到opcode为10的Hello事件后,首次心跳需要在
0 ~ heartbeat_interval的随机抖动区间内发送,你的代码直接按完整的heartbeat_interval延迟发送首次心跳,触发网关超时判定,服务端直接断开连接,因此不会再推送后续事件。 - 网关API版本过旧:你当前使用的v6版本网关早已被Discord正式停止服务,旧版本连接会被服务端强制限制,无法正常维持长连接。
- 缺少opcode为1的心跳请求处理逻辑:Discord运行过程中会主动推送opcode为1的心跳请求,要求客户端立刻回包,未处理该请求会被服务端判定为连接失效并主动断开。
- 未监听WebSocket的异常事件:你没有添加
error、close事件的监听逻辑,无法感知到连接已经被服务端断开,所以看不到连接终止的报错信息。
解决方案
- 调整首次心跳发送逻辑:按照官方规范添加首次心跳的随机抖动延迟,避免触发超时判定
- 升级网关API版本:将网关连接地址的版本号从v6更换为当前官方推荐的v10
- 新增op=1事件处理逻辑:收到服务端主动推送的心跳请求时,立刻返回心跳包
- 添加连接异常监听:补充错误、关闭事件的处理逻辑,方便问题排查和自动重连
修改后的参考代码
const botToken = token; // 升级为v10版本网关 const ws = new WebSocket("wss://gateway.discord.gg/?v=10&encoding=json"); let heartbeatInterval = 0; let session_id; let last_seq = null; const payload = { op: 2, d: { token: botToken, intents: 32767, properties: { $os: "linux", $browser: "chrome", $device: "chrome", }, }, }; ws.on("open", function open() { ws.send(JSON.stringify(payload)); }); ws.on("message", function incoming(data) { let response = JSON.parse(data); const { t, op, d, s } = response; if (s) last_seq = s; switch (op) { case 10: const { heartbeat_interval } = d; // 首次心跳添加随机抖动延迟 setTimeout(() => { sendHeartbeat(); // 首次心跳发送成功后开启固定间隔的心跳定时器 heartbeatInterval = setInterval(sendHeartbeat, heartbeat_interval); }, Math.random() * heartbeat_interval); break; case 1: // 收到服务端主动心跳请求,立刻回包 sendHeartbeat(); break; case 7: // 重连逻辑 ws.send(JSON.stringify({ op: 6, d: { token: botToken, session_id: session_id, last_seq: last_seq } })) break; } if(t == "READY") { session_id = d.session_id; console.log("session id: " + session_id) } const eventName = t + "Callback"; console.log(t) if(callbacks[eventName] && typeof callbacks[eventName] == "function") { callbacks[eventName](d); } }); // 封装心跳发送逻辑 const sendHeartbeat = () => { console.log("heartbeat sent") ws.send(JSON.stringify({ op: 3, d: last_seq })); }; // 添加异常事件监听 ws.on("error", (err) => { console.error("WebSocket error:", err); clearInterval(heartbeatInterval); }); ws.on("close", (code, reason) => { console.log("WebSocket closed, code:", code, "reason:", reason); clearInterval(heartbeatInterval); // 可在这里添加自动重连逻辑 });
内容的提问来源于stack exchange,提问作者BlackdestinyXX
相关产品推荐
相关产品推荐

