Discord.js V12中-dog命令频繁调用报错及ReferenceError问题的修复咨询
问题修复与优化方案
先解决最直接的ReferenceError问题:你在代码里用了title变量但从来没定义过!看你的逻辑,这个title应该是Reddit帖子的标题,也就是index.title——你已经拿到了index(帖子的data对象),只需要把title替换成index.title就行,同时还要调整text变量的作用域,避免后续逻辑里出现未定义的情况。
接下来一步步梳理代码里的问题并优化:
1. 修复未定义变量与重复逻辑
你的代码里有两处重复的if (index.post_hint !== 'image')判断,而且变量作用域混乱,导致text在第二个判断里可能未定义。另外,Discord.js v12里RichEmbed已经是MessageEmbed的别名,统一用MessageEmbed更规范。
修复后的核心代码:
const Discord = require('discord.js'); const https = require('https'); // 补上你缺失的https模块导入 const url = 'https://www.reddit.com/r/lookatmydog/hot/.json?limit=100'; module.exports = { name: 'dog', description: 'sends a dog!', execute(message, args) { https.get(url, (result) => { let body = ''; result.on('data', (chunk) => { body += chunk; }); result.on('end', () => { try { // 加try-catch处理JSON解析失败的情况 const response = JSON.parse(body); // 用数组实际长度替代硬编码的99,避免数组越界 const index = response.data.children[Math.floor(Math.random() * response.data.children.length)].data; const link = 'https://reddit.com' + index.permalink; const subRedditName = index.subreddit_name_prefixed; if (index.post_hint !== 'image') { // 非图片帖子处理逻辑 const text = index.selftext || 'No description provided.'; // 加默认值避免空文本 const textEmbed = new Discord.MessageEmbed() .setTitle(subRedditName) .setColor('RANDOM') .setDescription(`[${index.title}](${link})\n\n${text}`) // 替换为index.title .setURL(`https://reddit.com/${subRedditName}`); return message.channel.send(textEmbed); // 用return终止后续逻辑,避免重复发送 } // 图片帖子处理逻辑 const image = index.preview.images[0].source.url.replace('&', '&'); const imageEmbed = new Discord.MessageEmbed() .setTitle('Here is a dog, how nice!') .setImage(image) .setColor('RANDOM'); message.channel.send(imageEmbed); } catch (err) { console.error('Error parsing Reddit response:', err); message.channel.send('Oops, something went wrong fetching a dog!'); } }).on('error', function (e) { console.error('HTTP Request Error:', e); message.channel.send('Failed to fetch dog images. Try again later!'); }); }); }, };
这里做了这些关键优化:
- 补上缺失的
https模块导入 - 用
response.data.children.length替代硬编码的99,防止数组越界 - 给
text加默认值,避免帖子无描述时出现空内容 - 用
return终止非图片帖子的后续逻辑,避免同时发送文本和图片embed - 增加
try-catch处理JSON解析失败的异常 - 统一使用
MessageEmbed,移除过时的RichEmbed - 修复
title未定义的核心错误
2. 解决频繁调用的异常问题
频繁调用时出现的错误,主要来自两个方面:
原因1:Reddit API限流
Reddit对未认证的API请求有限流规则,短时间内大量请求会被拒绝,导致请求失败进而引发后续错误。
解决方案:缓存帖子列表
不用每次调用都请求Reddit,把请求到的帖子列表缓存起来,比如5分钟内复用同一批数据:
// 模块顶部添加缓存变量 let cachedPosts = []; let cacheExpiry = 0; // 把发送embed的逻辑抽成单独函数 function sendDogEmbed(message, posts) { const index = posts[Math.floor(Math.random() * posts.length)]; const link = 'https://reddit.com' + index.permalink; const subRedditName = index.subreddit_name_prefixed; if (index.post_hint !== 'image') { const text = index.selftext || 'No description provided.'; const textEmbed = new Discord.MessageEmbed() .setTitle(subRedditName) .setColor('RANDOM') .setDescription(`[${index.title}](${link})\n\n${text}`) .setURL(`https://reddit.com/${subRedditName}`); return message.channel.send(textEmbed); } const image = index.preview.images[0].source.url.replace('&amp;', '&'); const imageEmbed = new Discord.MessageEmbed() .setTitle('Here is a dog, how nice!') .setImage(image) .setColor('RANDOM'); message.channel.send(imageEmbed); } // 修改execute函数的请求逻辑 execute(message, args) { const now = Date.now(); // 缓存未过期且有数据时直接复用 if (now < cacheExpiry && cachedPosts.length > 0) { sendDogEmbed(message, cachedPosts); return; } // 缓存过期时发起新请求 https.get(url, (result) => { let body = ''; result.on('data', (chunk) => { body += chunk; }); result.on('end', () => { try { const response = JSON.parse(body); cachedPosts = response.data.children.map(child => child.data); // 缓存所有帖子数据 cacheExpiry = now + 5 * 60 * 1000; // 缓存5分钟 sendDogEmbed(message, cachedPosts); } catch (err) { console.error('Error parsing Reddit response:', err); message.channel.send('Oops, something went wrong fetching a dog!'); } }).on('error', function (e) { console.error('HTTP Request Error:', e); message.channel.send('Failed to fetch dog images. Try again later!'); }); }); }
原因2:Discord发送频率限制
Discord机器人短时间内发送大量消息会被限流,导致消息发送失败。
解决方案:添加命令冷却
用一个Map记录每个用户的最后调用时间,限制每5秒只能调用一次:
// 模块顶部添加冷却记录 const cooldowns = new Map(); // 在execute函数开头添加冷却逻辑 execute(message, args) { const userId = message.author.id; const cooldownTime = 5000; // 5秒冷却时间 if (cooldowns.has(userId)) { const remaining = (cooldowns.get(userId) + cooldownTime - Date.now()) / 1000; return message.reply(`Wait ${remaining.toFixed(1)} seconds before using this command again!`); } cooldowns.set(userId, Date.now()); setTimeout(() => cooldowns.delete(userId), cooldownTime); // ... 后续的缓存/请求逻辑 ... }
3. 其他优化建议
- 可以用
node-fetch替代原生https模块,代码会更简洁易读(需要先安装npm install node-fetch) - 给embed添加作者信息或footer,提升用户体验
- 增加对帖子无
preview字段的判断,避免出现新的报错
内容的提问来源于stack exchange,提问作者Blake ツ
相关产品推荐
相关产品推荐

