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

Discord Bot添加Reaction按钮更新MySQL数据时遇Unknown Emoji错误

Discord Bot问题:Reaction报错与功能实现需求

问题描述

我开发的Discord Bot从MySQL拉取数据并发送Embed消息,尝试添加Reaction功能更新数据库时,一直触发DiscordAPIError[10014]: Unknown Emoji错误;就算只发送Embed消息,也会在消息发送前报错。需要实现:单命令发送多条Embed消息,且通过Reaction按钮更新MySQL数据库。

报错信息

throw new DiscordAPIError(data, "code" in data ? data.code : data.error, status, method, url, requestData);
      ^

DiscordAPIError[10014]: Unknown Emoji
    at SequentialHandler.runRequest (D:\BotDc\node_modules\@discordjs\rest\dist\index.js:667:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async SequentialHandler.queueRequest (D:\BotDc\node_modules\@discordjs\rest\dist\index.js:464:14)
    at async REST.request (D:\BotDc\node_modules\@discordjs\rest\dist\index.js:910:22)
    at async MessageManager.react (D:\BotDc\node_modules\discord.js\src\managers\MessageManager.js:242:5)
    at async Message.react (D:\BotDc\node_modules\discord.js\src\structures\Message.js:760:5)
    at async Query.onResult (D:\BotDc\index.js:48:11) {
  rawError: { message: 'Unknown Emoji', code: 10014 },
  code: 10014,
  status: 400,
  method: 'PUT',
  url: 'https://discord.com/api/v10/channels/745223942976962590/messages/1056802702929186836/reactions/1%3F%3F/@me'
}

现有代码

const Discord = require('discord.js');
const fs = require('fs');
const path = require('path');
const mysql = require('mysql2');

const { token } = require('./config.json');

const client = new Discord.Client({ intents: [Discord.GatewayIntentBits.Guilds] });

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '',
  database: 'continue_web'
});

connection.connect((err) => {
  if (err) throw err;
  console.log('Connected to MySQL database');
});

client.once(Discord.Events.ClientReady, c => {
  client.commands = new Discord.Collection();
  client.on(Discord.Events.InteractionCreate, async interaction => {
    if (!interaction.isChatInputCommand()) return;
    if (interaction.commandName === 'ping') {
connection.query("SELECT * , CASE sex WHEN 1 THEN 'Laki-Laki' WHEN 2 THEN 'Perempuan' END AS gender_text FROM accounts WHERE gauth_status='pending'", async (error, results) => {
  if (error) throw error;
  for (const result of results) {
    const exampleEmbed = new Discord.EmbedBuilder()
      .setColor(0x0099FF)
      .setTitle(result.nickname)
      .setURL('https://discord.js.org/')
      .setAuthor({ name: result.nickname , iconURL: 'https://continue-rp.my.id/forum/data/avatars/m/0/1.jpg?1671348397', url: 'https://discord.js.org' })
      .setDescription('Request Character Story')
      .addFields({ name: 'Story:', value: result.ucpmail , inline: false })
      .addFields({ name: 'Umur:', value: result.age + ' Tahun' , inline: true })
      .addFields({ name: 'Gender:', value: result.gender_text , inline: true })
      .addFields({
        name: 'Actions:',
        value: ':one: Approve\n:two: Reject',
        inline: true
      })
      .setTimestamp()
      .setFooter({ text: 'Character Dibuat:'+ '\n'+ result.create_date , iconURL: 'https://continue-rp.my.id/forum/data/avatars/m/0/1.jpg?1671348397' });
    await interaction.channel.send({ embeds: [exampleEmbed] });
  }
});

    }
  });
  console.log(`Ready! Logged in as ${c.user.tag}`);
});

client.login(token);

解决方案

1. 修复Unknown Emoji错误

报错原因是添加Reaction时使用了:one:这类Discord表情别名,而Discord API需要原生表情字符或自定义表情ID。对于原生数字表情,直接用1️⃣、2️⃣这类字符即可。发送Embed后需保存消息对象,再调用react()方法添加反应。

2. 补充必要的Intents

要监听Reaction事件,必须添加GuildMessageReactions权限,若需处理消息内容可补充MessageContent,修改客户端初始化代码:

const client = new Discord.Client({ 
  intents: [
    Discord.GatewayIntentBits.Guilds,
    Discord.GatewayIntentBits.GuildMessageReactions,
    Discord.GatewayIntentBits.MessageContent
  ] 
});

3. 关联Reaction与数据库记录

用Collection存储消息ID和数据库记录ID的映射,确保点击Reaction时能找到对应的数据库条目。也可将记录ID嵌入Embed的footer中作为标识。

4. 监听Reaction事件更新数据库

添加messageReactionAdd事件监听,判断用户点击的表情,执行对应的数据库更新操作,并同步修改Embed状态。

修改后的完整代码

const Discord = require('discord.js');
const mysql = require('mysql2');

const { token } = require('./config.json');

// 补充必要的Intents
const client = new Discord.Client({ 
  intents: [
    Discord.GatewayIntentBits.Guilds,
    Discord.GatewayIntentBits.GuildMessageReactions,
    Discord.GatewayIntentBits.MessageContent
  ] 
});

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '',
  database: 'continue_web'
});

connection.connect((err) => {
  if (err) throw err;
  console.log('Connected to MySQL database');
});

// 存储消息ID与数据库account ID的映射
const messageAccountMap = new Discord.Collection();

client.once(Discord.Events.ClientReady, c => {
  console.log(`Ready! Logged in as ${c.user.tag}`);

  client.on(Discord.Events.InteractionCreate, async interaction => {
    if (!interaction.isChatInputCommand()) return;
    if (interaction.commandName === 'ping') {
      // 先回复用户避免命令超时
      await interaction.deferReply({ ephemeral: true });

      connection.query("SELECT * , CASE sex WHEN 1 THEN 'Laki-Laki' WHEN 2 THEN 'Perempuan' END AS gender_text FROM accounts WHERE gauth_status='pending'", async (error, results) => {
        if (error) {
          console.error(error);
          return interaction.editReply('查询数据库出错');
        }

        if (results.length === 0) {
          return interaction.editReply('没有待处理的请求');
        }

        for (const result of results) {
          const exampleEmbed = new Discord.EmbedBuilder()
            .setColor(0x0099FF)
            .setTitle(result.nickname)
            .setAuthor({ name: result.nickname , iconURL: 'https://continue-rp.my.id/forum/data/avatars/m/0/1.jpg?1671348397' })
            .setDescription('Request Character Story')
            .addFields(
              { name: 'Story:', value: result.ucpmail , inline: false },
              { name: 'Umur:', value: `${result.age} Tahun` , inline: true },
              { name: 'Gender:', value: result.gender_text , inline: true },
              { name: 'Actions:', value: '1️⃣ Approve\n2️⃣ Reject', inline: true }
            )
            .setTimestamp()
            .setFooter({ text: `Character Dibuat: ${result.create_date} | ID: ${result.id}`, iconURL: 'https://continue-rp.my.id/forum/data/avatars/m/0/1.jpg?1671348397' });

          // 发送消息并保存对象
          const sentMessage = await interaction.channel.send({ embeds: [exampleEmbed] });
          // 存储映射关系
          messageAccountMap.set(sentMessage.id, result.id);
          // 添加反应
          await sentMessage.react('1️⃣');
          await sentMessage.react('2️⃣');
        }

        await interaction.editReply(`已发送 ${results.length} 条待处理请求`);
      });
    }
  });

  // 监听Reaction添加事件
  client.on(Discord.Events.MessageReactionAdd, async (reaction, user) => {
    // 忽略机器人自身的反应
    if (user.bot) return;

    // 获取对应的account ID
    const accountId = messageAccountMap.get(reaction.message.id);
    if (!accountId) return;

    // 判断点击的表情
    let newStatus;
    if (reaction.emoji.name === '1️⃣') {
      newStatus = 'approved';
    } else if (reaction.emoji.name === '2️⃣') {
      newStatus = 'rejected';
    } else {
      return; // 忽略其他表情
    }

    // 更新数据库
    connection.query('UPDATE accounts SET gauth_status = ? WHERE id = ?', [newStatus, accountId], (error, results) => {
      if (error) {
        console.error(error);
        user.send(`更新ID为${accountId}的记录时出错`).catch(console.error);
        return;
      }

      // 更新Embed状态
      const embed = reaction.message.embeds[0];
      const updatedEmbed = Discord.EmbedBuilder.from(embed)
        .setColor(newStatus === 'approved' ? 0x00FF00 : 0xFF0000)
        .addFields({ name: 'Status:', value: newStatus.charAt(0).toUpperCase() + newStatus.slice(1), inline: true });

      reaction.message.edit({ embeds: [updatedEmbed] });
      // 移除映射避免重复处理
      messageAccountMap.delete(reaction.message.id);
      // 移除所有反应
      reaction.message.reactions.removeAll().catch(console.error);
      user.send(`已成功将ID为${accountId}的请求设置为${newStatus}`).catch(console.error);
    });
  });
});

client.login(token);

关键说明

  • 用interaction.deferReply()避免命令超时,因为查询数据库和发送多条消息可能耗时较长。
  • messageAccountMap确保Reaction操作能精准对应到数据库条目。
  • 处理完Reaction后更新Embed状态、移除反应和映射,防止重复操作。

内容的提问来源于stack exchange,提问作者Nanang Ma'ruf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 10:21:13