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

如何用JavaScript版Discord Bot获取频道所有消息?

问题:Discord示例Bot中实现/getmessages命令获取频道消息失败

我已成功运行Discord官方入门示例项目,/test命令可正常响应,还创建了新命令/getmessages,目前仅返回固定字符串。
命令运行截图

我希望修改该命令以获取频道内所有消息,尝试参考获取频道消息的代码方案,但实现时遇到问题。

参考代码示例:

const channel = client.channels.cache.get("Your channel ID");
channel.messages.fetch({ limit: 100 }).then(messages => {
  console.log(`Received ${messages.size} messages`);
  // 遍历消息
  messages.forEach(message => console.log(message.content))
})

我将获取频道的代码添加到自己的JavaScript代码中:

if (name === 'getmessages') {
  // 获取当前频道所有消息
  console.log("try to get messages")

  try{
    const channel = client.channels.cache.get("961001859659759751");
  }catch(err){
    console.log("ERROR GETTING CHANNEL: ", err)
  }

  // 回复触发命令的频道
  return res.send({
    type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
    data: {
      content: '2. Hello we will try to get messages ' + getRandomEmoji(),
    },
  });
}

运行后出现错误:

ERROR GETTING CHANNEL:  ReferenceError: client is not defined

我不确定这是否是在Discord示例JavaScript Bot中获取频道消息的正确方式,也不清楚当前app.js里的client变量是什么,我的完整app.js代码如下:

import 'dotenv/config';
import express from 'express';
import {
  InteractionType,
  InteractionResponseType,
  InteractionResponseFlags,
  MessageComponentTypes,
  ButtonStyleTypes,
} from 'discord-interactions';
import { VerifyDiscordRequest, getRandomEmoji, DiscordRequest } from './utils.js';
import { getShuffledOptions, getResult } from './game.js';

// create client var
//export class Client<Ready extends boolean = boolean> extends BaseClient;

// 创建express应用
const app = express();
// 端口,默认3000
const PORT = process.env.PORT || 3000;
// 解析请求体并验证Discord请求
app.use(express.json({ verify: VerifyDiscordRequest(process.env.PUBLIC_KEY) }));

// 存储进行中的游戏,生产环境建议用数据库
const activeGames = {};

/**
 * Discord交互请求的端点
 */
app.post('/interactions', async function (req, res) {
  // 交互类型和数据
  const { type, id, data } = req.body;

  /**
   * 处理PING验证请求
   */
  if (type === InteractionType.PING) {
    return res.send({ type: InteractionResponseType.PONG });
  }

  /**
   * 处理斜杠命令请求
   */
  if (type === InteractionType.APPLICATION_COMMAND) {
    const { name } = data;

    // "getMessages"命令
    if (name === 'getmessages') {
      // 获取当前频道所有消息
      console.log("try to get messages")

      try{
        const channel = client.channels.cache.get("961001859659759751");
      }catch(err){
        console.log("ERROR GETTING CHANNEL: ", err)
      }

      // 回复触发命令的频道
      return res.send({
        type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
        data: {
          content: '2. Hello we will try to get messages ' + getRandomEmoji(),
        },
      });
    }
    // "test"命令
    if (name === 'test') {
      // 回复触发命令的频道
      return res.send({
        type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
        data: {
          content: 'hello world ' + getRandomEmoji(),
        },
      });
    }
    // "challenge"命令
    if (name === 'challenge' && id) {
      const userId = req.body.member.user.id;
      // 用户选择的物品
      const objectName = req.body.data.options[0].value;

      // 用消息ID作为游戏ID创建游戏实例
      activeGames[id] = {
        id: userId,
        objectName,
      };

      return res.send({
        type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
        data: {
          content: `Rock papers scissors challenge from <@${userId}>`,
          components: [
            {
              type: MessageComponentTypes.ACTION_ROW,
              components: [
                {
                  type: MessageComponentTypes.BUTTON,
                  custom_id: `accept_button_${req.body.id}`,
                  label: 'Accept',
                  style: ButtonStyleTypes.PRIMARY,
                },
              ],
            },
          ],
        },
      });
    }
  }

  /**
   * 处理交互组件请求
   */
  if (type === InteractionType.MESSAGE_COMPONENT) {
    // 组件自定义ID
    const componentId = data.custom_id;

    if (componentId.startsWith('accept_button_')) {
      // 获取关联的游戏ID
      const gameId = componentId.replace('accept_button_', '');
      // 删除原消息的端点
      const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`;
      try {
        await res.send({
          type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
          data: {
            content: 'What is your object of choice?',
            flags: InteractionResponseFlags.EPHEMERAL,
            components: [
              {
                type: MessageComponentTypes.ACTION_ROW,
                components: [
                  {
                    type: MessageComponentTypes.STRING_SELECT,
                    custom_id: `select_choice_${gameId}`,
                    options: getShuffledOptions(),
                  },
                ],
              },
            ],
          },
        });
        // 删除之前的消息
        await DiscordRequest(endpoint, { method: 'DELETE' });
      } catch (err) {
        console.error('Error sending message:', err);
      }
    } else if (componentId.startsWith('select_choice_')) {
      // 获取关联的游戏ID
      const gameId = componentId.replace('select_choice_', '');

      if (activeGames[gameId]) {
        // 获取响应用户的ID和选择
        const userId = req.body.member.user.id;
        const objectName = data.values[0];
        // 计算游戏结果
        const resultStr = getResult(activeGames[gameId], {
          id: userId,
          objectName,
        });

        // 从存储中移除游戏
        delete activeGames[gameId];
        // 更新消息的端点
        const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`;

        try {
          // 发送结果
          await res.send({
            type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
            data: { content: resultStr },
          });
          // 更新临时消息
          await DiscordRequest(endpoint, {
            method: 'PATCH',
            body: {
              content: 'Nice choice ' + getRandomEmoji(),
              components: [],
            },
          });
        } catch (err) {
          console.error('Error sending message:', err);
        }
      }
    }
  }
});

app.listen(PORT, () => {
  console.log('Listening on port', PORT);
});

解决方案

问题根源

你使用的Discord官方入门示例是基于HTTP交互模式(通过Express接收Discord的Webhook请求),而非传统的Discord.js客户端(Client类)。代码中从未初始化过client变量,因此会报错client is not defined。

正确实现方式

要在这个示例中获取频道消息,需使用Discord API的REST接口,利用示例中已有的DiscordRequest工具函数调用API即可。

修改后的/getmessages命令代码:

if (name === 'getmessages') {
  console.log("try to get messages");
  // 从请求体中获取当前频道ID(无需硬编码)
  const channelId = req.body.channel_id;
  try {
    // 调用Discord API获取频道消息,单次最多获取100条
    const messages = await DiscordRequest(`/channels/${channelId}/messages?limit=100`, { method: 'GET' });
    // 提取消息内容并拼接成字符串
    const messageContents = messages.map(msg => `${msg.author.username}: ${msg.content}`).join('\n');
    // 回复用户,注意Discord消息内容有2000字符限制,超出需截断
    return res.send({
      type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
      data: {
        content: `获取到${messages.length}条消息:\n${messageContents.length > 1900 ? messageContents.slice(0,1900)+'...' : messageContents}`,
      },
    });
  } catch(err) {
    console.log("ERROR GETTING MESSAGES: ", err);
    return res.send({
      type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
      data: {
        content: '获取消息失败:'+err.message,
      },
    });
  }
}

注意事项

  • 确保Bot拥有Read Message History权限
  • Discord API限制单次最多获取100条消息,如需获取更多需通过before参数分页循环请求
  • 单条消息内容不能超过2000字符,超出需截断或拆分回复

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:53:10