discord.js响应交互时向MessageEmbed附加文件失败问题
问题根因
你遇到的DiscordAPIError: Unknown interaction错误码10062,核心原因是Discord交互的响应令牌有效期仅为3秒,你当前的代码逻辑在触发交互后没有在3秒内给出响应,导致令牌失效。
- 不带附件时,文件读取、Embed生成的总耗时刚好卡在3秒阈值内,所以能正常返回
- 携带附件时,多了附件序列化、上传预处理的开销,总耗时超过3秒,Discord侧已经销毁了该交互记录,因此返回未知交互错误
解决方案
1. 提前给交互发送延迟响应(必改)
对于需要进行异步IO(比如读本地文件、请求接口)的交互逻辑,必须在3秒内先调用deferReply占位,将交互的有效响应时间延长到15分钟。
2. 优化异步逻辑,避免回调地狱
将回调式的fs.readFile改为Promise版本,配合async/await简化异步流程,同时提前缓存静态数据避免重复读磁盘。
3. 延迟响应完成后使用editReply返回最终内容
修改后代码
sdg函数修改
const Discord = require('discord.js'); const fs = require('fs/promises'); // 改用Promise版本的fs const path = require('path'); const p = path.join(__dirname, '..', 'static', 'SDGs.json'); // 提前缓存SDG数据,避免每次调用都读磁盘 let sdgCache = null; (async () => { try { const data = await fs.readFile(p); sdgCache = JSON.parse(data); } catch (err) { console.error('SDG数据加载失败:', err.message); } })(); module.exports = async (msg, int, text, sDGNo) => { // 如果是交互触发,先发送延迟响应 if (int) { await int.deferReply(); } // 等待缓存加载完成(如果还没加载完的话) while (!sdgCache) { await new Promise(resolve => setTimeout(resolve, 100)); } if (Number(sDGNo) === 0) { const imgFilePath = path.join(__dirname, '..', 'static', 'SDGIcons', 'SDG_Wheel_Transparent_WEB.png'); const imgAttachment = new Discord.MessageAttachment(imgFilePath, 'SDG_Wheel_Transparent_WEB.png'); const goals = []; for (let i = 1; i < 18; i++) { const sdg = sdgCache[i]; goals.push({ name: `${i} ${sdg.shortForm}`, value: `${sdg.shortFormJap}\n${sdg.shortFormNep}`, inline: true }); } const embed = new Discord.MessageEmbed() .setTitle('Sustainable Development Goals') .setColor('#ffffff') .setThumbnail('attachment://SDG_Wheel_Transparent_WEB.png') .addFields(goals) .setFooter('To find out more about each goal, simply type "!sdg" and the goal number (e.g., "!sdg7").'); if (msg) { await msg.channel.send({ embeds: [embed], files: [imgAttachment] }); } else if (int) { // 延迟响应后用editReply替换内容 await int.editReply({ embeds: [embed], files: [imgAttachment] }); } return; } }
interactionCreate事件修改
const { nE, tJ, say, whatis, spellcheck, joke, syn, ant, tN, sdg } = require('../helpers/commands'); module.exports = (client, interaction) => { switch (interaction.commandName) { /* ... */ case 'sdg': // 调用async函数,捕获异常避免崩溃 sdg(null, interaction, null, interaction.options.data[0] ? interaction.options.data[0].value : '0').catch(console.error); break; } };
补充注意点
- 如果你使用的是discord.js v14及以上版本,
MessageAttachment、MessageEmbed已经从discord.js主包移到了discord.js/builders包下,需要对应调整导入路径 - 本地静态资源如果是固定不变的,也可以提前上传到CDN,直接给Embed的thumbnail填CDN链接,不用每次都传本地文件,能进一步提升响应速度
内容的提问来源于stack exchange,提问作者dale8nson
相关产品推荐
相关产品推荐

