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

Discord Websocket保持连接但一段时间后停止接收消息事件

问题分析与修复方案

你的问题核心是Discord网关会话进入无效状态,但心跳机制仍在运行,导致连接看似正常但无法接收事件。以下是代码中的关键问题及修复方案:

1. 未处理网关关键控制指令

Discord网关会通过特定OP码通知客户端状态变更,你的代码缺少对这些指令的处理:

  • OP 7 (Reconnect):网关要求客户端主动重连,若不处理会导致后续事件丢失
  • OP 9 (Invalid Session):当前会话已失效,需重新发起Identify而非Resume

2. 心跳定时器未清理

每次重连时,旧的心跳定时器未被清除,导致多个心跳任务同时运行,干扰网关状态。

3. Resume逻辑边界缺失

当会话过期时仍尝试Resume,会陷入无效循环,需在Invalid Session时重置会话信息,重新走Identify流程。


修复后的代码

const WebSocket = require('ws');
const listenerjs = require("./listener.js");

const initialURL = "wss://gateway.discord.gg";
const userToken = "Token";
let url = initialURL,
    sessionID = "";
let ws;
let interval = 0,
    seq = -1;

const payload = {
    op: 2,
    d: {
        token: userToken,
        intents: 33280,
        properties: {
            $os: "windows",
            $browser: "chrome",
            $device: "chrome",
        }
    }
}

const heartbeat = (ms) => {
    return setInterval(() => {
        if (ws?.readyState === WebSocket.OPEN) {
            console.log("Heartbeat Sent!")
            ws.send(JSON.stringify({ op: 1, d: seq }));
        }
    }, ms);
};

const clearHeartbeat = () => {
    if (interval) {
        clearInterval(interval);
        interval = 0;
    }
};

const initializeWebsocket = () => {
    // 清理旧连接和定时器
    clearHeartbeat();
    if (ws && ws.readyState !== WebSocket.CLOSED) {
        ws.close(1000, "Reconnecting");
    }

    let wasReady = false;

    ws = new WebSocket(url + "/?v=10&encoding=json"); 

    ws.on("open", function open() {
        if (url !== initialURL && sessionID && seq !== -1) {
            console.log("Attempting to resume session");
            const resumePayload = {
                op: 6,
                d: {
                    token: userToken,
                    session_id: sessionID,
                    seq: seq
                }
            }
            ws.send(JSON.stringify(resumePayload))
        } else {
            // 首次连接或会话失效,发起Identify
            ws.send(JSON.stringify(payload))
        }
    });

    ws.on("error", function error(e){
        console.error("Gateway error:", e);
    });

    ws.on("close", function close(code, reason){
        if (wasReady) {
            console.log(`Gateway closed (${code}): ${reason}, reconnecting in 7.5s`);
        }
        setTimeout(() => {
            initializeWebsocket();
        }, 7500);
    });

    ws.on("message", function incoming(data){
        let p = JSON.parse(data);
        const { t, op, d, s } = p;

        // 更新序列值(所有带s的包都要更新)
        if (s !== undefined) {
            seq = s;
        }

        switch(op){
            case 0:
                // 普通事件,已通过上面更新seq
                break;
            case 7:
                // 网关要求重连
                console.log("Gateway requested reconnect");
                initializeWebsocket();
                break;
            case 9:
                // 无效会话,重置信息重新Identify
                console.log("Invalid session, resetting and re-identifying");
                sessionID = "";
                seq = -1;
                url = initialURL;
                initializeWebsocket();
                break;
            case 10:
                const { heartbeat_interval } = d;
                clearHeartbeat(); // 确保没有旧定时器
                interval = heartbeat(heartbeat_interval);
                wasReady = true;
                break;
            case 11:
                const today = new Date();
                const dateTime = `${today.getFullYear()}-${String(today.getMonth()+1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')} ${String(today.getHours()).padStart(2, '0')}:${String(today.getMinutes()).padStart(2, '0')}:${String(today.getSeconds()).padStart(2, '0')}`;
                console.log(`Heartbeat Received! ${dateTime}`);
                break;
        }

        switch(t){
            case "READY":
                console.log("Gateway Connection Ready!");
                url = d.resume_gateway_url;
                sessionID = d.session_id;
                break;
            case "RESUMED":
                console.log("Gateway Connection Resumed");
                break;
            case "MESSAGE_CREATE":
                listenerjs.listener(d);
                break;
        }
    })
}

initializeWebsocket();

关键修复点说明

  • 新增OP 7和OP 9处理:主动响应网关的重连要求,会话失效时重置状态重新初始化
  • 心跳定时器清理:每次重连前清除旧定时器,避免重复发送心跳
  • 完善Resume条件:只有当sessionID和seq有效时才尝试Resume,否则直接Identify
  • 心跳包携带seq:按Discord规范携带当前seq,帮助网关确认会话状态
  • 增强日志与错误处理:便于排查连接状态问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:27:39