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

Cloudflare Workers中Discord Bot无法连接网关更新状态问题

Cloudflare Workers中Discord网关WebSocket连接失败问题解决

问题描述

我有一个部署在Cloudflare Workers上的Discord Bot,想要通过Discord网关更新在线状态。以下代码在浏览器控制台中可以正常运行,但在Workers环境下完全失效:

export function setPresence(token: string) {
    return new Promise((resolve, reject) => {
        const activities = [{
            name: `you`,
            type: 3
        }];
        const socket = new WebSocket("wss://gateway.discord.gg/?v=10&encoding=json");

        function send(op, d) {
            return socket.send(JSON.stringify({ op, d }));
        }

        socket.addEventListener("error", e => console.error(e) || reject(e));
        socket.addEventListener("open", _ => console.log("websocket open"));
        socket.addEventListener("close", _ => console.log("websocket closed") || resolve());
        socket.addEventListener("message", event => {
            const data = JSON.parse(event.data);
            const { op, d } = data;
            console.log({ data });

            switch (op) {
                case 1: // Heartbeat
                case 10: { // Hello
                    send(1, null);
                    break;
                };
                case 11: { // Heartbeat ACK
                    send(2, {
                        token,
                        properties: {
                            os: "linux",
                            browser: "cloudflare workers",
                            device: "cloudflare workers"
                        },
                        intents: 0
                    });
                    break;
                }
                case 0: { // Ready
                    console.log("websocket ready");
                    send(3, {
                        activities: [activities[Math.floor(activities.length * Math.random())]],
                        status: "online",
                        since: 91879201,
                        afk: false
                    });
                    setTimeout(_ => socket.close(), 10000);
                }
            }
        });
    });
}

运行差异:

  • 浏览器环境:WebSocket能正常建立连接,完成身份验证并更新状态(浏览器正常运行截图)
  • Workers环境(wrangler dev --remote):无"websocket open"日志,仅触发错误事件和"websocket closed"日志(Workers运行报错截图)
  • 尝试通过fetch("https://gateway.discord.gg/?v=10&encoding=json")获取响应的webSocket属性,结果始终为null

问题原因

Cloudflare Workers的WebSocket实现与浏览器存在核心差异:

  1. 连接创建方式限制:Workers不支持直接通过new WebSocket()创建客户端连接,必须通过fetch API的webSocket属性初始化连接,这是环境强制要求。
  2. Discord网关协议适配:原代码中Hello包(op=10)的心跳响应参数错误,不符合Discord网关规范,会导致连接被主动断开。

解决方案

修改代码,适配Workers的WebSocket规则并修正协议逻辑:

export async function setPresence(token: string) {
    const activities = [{
        name: `you`,
        type: 3
    }];

    // 通过fetch初始化WebSocket连接
    const response = await fetch("wss://gateway.discord.gg/?v=10&encoding=json", {
        method: "GET",
        headers: {
            "Upgrade": "websocket",
            "Connection": "Upgrade"
        }
    });

    if (!response.webSocket) {
        throw new Error("无法从fetch响应获取WebSocket连接");
    }

    const socket = response.webSocket;
    socket.accept(); // 必须调用accept()确认连接

    function send(op: number, d: any) {
        socket.send(JSON.stringify({ op, d }));
    }

    return new Promise<void>((resolve, reject) => {
        socket.addEventListener("error", (e) => {
            console.error(e);
            reject(e);
        });

        socket.addEventListener("open", () => {
            console.log("websocket open");
        });

        socket.addEventListener("close", () => {
            console.log("websocket closed");
            resolve();
        });

        socket.addEventListener("message", (event) => {
            const data = JSON.parse(event.data);
            const { op, d } = data;
            console.log({ data });

            switch (op) {
                case 1: // Heartbeat
                case 10: { // Hello
                    // 发送心跳时携带Hello包返回的心跳间隔参数
                    send(1, d?.heartbeat_interval || null);
                    break;
                }
                case 11: { // Heartbeat ACK
                    send(2, {
                        token,
                        properties: {
                            os: "linux",
                            browser: "cloudflare workers",
                            device: "cloudflare workers"
                        },
                        intents: 0
                    });
                    break;
                }
                case 0: { // Ready
                    console.log("websocket ready");
                    send(3, {
                        activities: [activities[Math.floor(activities.length * Math.random())]],
                        status: "online",
                        since: 91879201,
                        afk: false
                    });
                    setTimeout(() => socket.close(), 10000);
                    break;
                }
            }
        });
    });
}

关键修改说明

  • fetch创建WebSocket:Workers环境要求必须通过指定Upgrade和Connection头的fetch请求建立WebSocket连接,不能直接实例化WebSocket对象。
  • 调用socket.accept():获取到WebSocket对象后必须调用此方法,否则连接会被立即关闭。
  • 修正心跳参数:Hello包返回的heartbeat_interval需要作为心跳包(op=1)的参数发送,原代码传null不符合Discord网关协议,会导致连接异常断开。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 00:07:52