discord.js开发Discord机器人调用Steam API嵌入消息报EMBED_FIELD_VALUE错
问题描述
- 开发场景:基于discord.js开发Discord机器人,需求为调用Steam API获取游戏实时在线人数,将返回数据嵌入消息发送到频道
- 故障现象:代码运行时直接崩溃,终端抛出
RangeError [EMBED_FIELD_VALUE]: MessageEmbed field values must be non-empty strings错误 - 原实现代码:
const gtaUrl = 'https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?key=KEY&format=json&appid=271590' let gtaData =''; request(gtaUrl,function(err,res,body){ if(!err&&res.statusCode<400){ gtaData +=body; } }) const exampleEmbed = new MessageEmbed() .setColor('#0099ff') .setTitle('Showing concurrent player numbers for some games') .setDescription('the game') .setThumbnail('https://i.imgur.com/FNviTdG.jpeg') .addFields( { name: 'tf2 ', value: gtaData }, ) .addField('Inline field title', 'Some value here', true) .setImage('https://i.imgur.com/AfFp7pu.png') .setTimestamp() message.channel.send({ embeds: [exampleEmbed] });
- 完整报错栈:
if (!allowEmpty && data.length === 0) throw new error(errorMessage); RangeError [EMBED_FIELD_VALUE]: MessageEmbed field values must be non-empty strings. at Util.verifyString (D:\Code\discordBot\node_modules\discord.js\src\util\Util.js:428:49) at MessageEmbed.normalizeField (D:\Code\discordBot\node_modules\discord.js\src\structures\MessageEmbed.js:544:19) at D:\Code\discordBot\node_modules\discord.js\src\structures\MessageEmbed.js:565:14 at Array.map () at MessageEmbed.normalizeFields (D:\Code\discordBot\node_modules\discord.js\src\structures\MessageEmbed.js:564:8) at MessageEmbed.addFields (D:\Code\discordBot\node_modules\discord.js\src\structures\MessageEmbed.js:328:42) at steamStatus (D:\Code\discordBot\src\bot.js:112:3) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { [Symbol(code)]: 'EMBED_FIELD_VALUE' }
根因分析
你的判断完全准确:
- 基于回调的
request请求是异步非阻塞逻辑,JavaScript主线程不会等待接口返回、回调执行完成,就会直接往下执行构造MessageEmbed、发送消息的逻辑 - 构造嵌入消息时,
gtaData还是初始化的空字符串,触发discord.js的字段非空校验,直接抛出错误 - 原逻辑存在额外缺陷:未对Steam返回的JSON数据做解析格式化,即使拿到数据直接塞原始JSON字符串可读性也很差,同时缺少请求异常处理分支,接口报错时会直接崩溃
修复方法
使用async/await语法改写异步逻辑,等接口请求完成、数据处理完毕后,再构造嵌入消息发送。Node.js 18及以上版本内置了fetchAPI,不需要额外安装第三方请求库,修复后代码如下:
// 注意:包裹该逻辑的函数必须添加async关键字 async function sendSteamPlayerEmbed(message) { const gtaUrl = 'https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?key=KEY&format=json&appid=271590' try { // 等待接口请求完成 const res = await fetch(gtaUrl) if (!res.ok) throw new Error(`接口请求异常,状态码:${res.status}`) // 解析返回的JSON数据,提取需要的在线人数字段 const playerData = await res.json() const playerCount = playerData.response.player_count // 确认数据拿到后再构造嵌入消息 const exampleEmbed = new MessageEmbed() .setColor('#0099ff') .setTitle('Showing concurrent player numbers for some games') .setDescription('Steam游戏实时在线人数') .setThumbnail('https://i.imgur.com/FNviTdG.jpeg') .addFields( { name: 'GTA5 实时在线人数', value: `${playerCount}` }, // 其他游戏的查询字段可按相同逻辑追加 ) .addField('数据更新时间', new Date().toLocaleString(), true) .setImage('https://i.imgur.com/AfFp7pu.png') .setTimestamp() // 执行发送操作 message.channel.send({ embeds: [exampleEmbed] }); } catch (err) { console.error('获取Steam数据失败:', err) message.channel.send('获取游戏在线人数失败,请稍后再试') } } // 调用函数传入message对象即可 sendSteamPlayerEmbed(message)
如果你使用的是Node.js 18以下版本,可以先安装
node-fetch包实现相同逻辑,也可以将原有request回调封装为Promise版本再用await等待结果,核心规则不变:必须等接口数据返回、处理完成后,再构造嵌入对象、执行发送操作。
内容的提问来源于stack exchange,提问作者Constantine Jon
相关产品推荐
相关产品推荐

