discord.js开发Discord音乐Bot出现connection未定义报错如何解决
问题原因分析
- 队列Map作用域错误:你在
play函数内部每次执行都重新初始化了const queue = new Map(),这个Map是局部变量,每次调用play都会清空,根本拿不到之前存储的serverQueue对象,自然不存在connection属性。 - serverQueue对象未初始化connection字段:你需要在用户首次触发播放命令、把歌曲加入队列的阶段,就完成加入语音频道、获取connection对象并存入serverQueue的操作,而不是在play函数里再去获取。
修复步骤
- 把队列Map移到play函数外部,变成全局/模块级变量,保证整个运行过程中只有一个队列实例:
// 放到play函数外面,全局作用域 const queue = new Map() function play(guild, song) { const serverQueue = queue.get(guild.id); // 剩下原有代码 }
- 在处理播放命令的消息回调逻辑里,提前创建serverQueue、获取connection,示例如下:
// 你的消息监听逻辑里的播放命令处理部分 client.on('messageCreate', async message => { // 跳过机器人消息、无前缀消息 if (!message.content.startsWith('!') || message.author.bot) return const args = message.content.slice(1).split(' ') const command = args.shift().toLowerCase() if (command === 'play') { const voiceChannel = message.member.voice.channel // 校验用户是否在语音频道 if (!voiceChannel) return message.channel.send('你需要先加入一个语音频道') // 校验Bot的语音权限 const permissions = voiceChannel.permissionsFor(message.client.user) if (!permissions.has('CONNECT') || !permissions.has('SPEAK')) { return message.channel.send('我没有加入该语音频道或发言的权限') } // 解析歌曲信息(你自己的ytdl解析逻辑) const songInfo = await ytdl.getInfo(args[0]) const song = { title: songInfo.videoDetails.title, url: songInfo.videoDetails.video_url, } // 检查当前服务器有没有已存在的队列 const serverQueue = queue.get(message.guild.id) if (!serverQueue) { // 新建队列对象 const queueConstruct = { textChannel: message.channel, voiceChannel: voiceChannel, connection: null, songs: [], volume: 5, playing: true } queue.set(message.guild.id, queueConstruct) queueConstruct.songs.push(song) try { // 加入语音频道,获取connection并存入队列 const connection = await voiceChannel.join() queueConstruct.connection = connection // 调用play函数开始播放 play(message.guild, queueConstruct.songs[0]) } catch (err) { console.log(err) queue.delete(message.guild.id) return message.channel.send(err) } } else { // 已有队列就直接加歌 serverQueue.songs.push(song) return message.channel.send(`${song.title} 已加入播放队列`) } } })
- 给play函数加serverQueue存在性校验,避免无队列时报错:
function play(guild, song) { const serverQueue = queue.get(guild.id); // 新增校验:没有队列直接返回 if (!serverQueue) return if (!song) { serverQueue.voiceChannel.leave(); queue.delete(guild.id); return; } const dispatcher = serverQueue.connection .play(ytdl(song.url, { filter: 'audioonly' })) // 建议加audioonly过滤,减少带宽占用 .on("finish", () => { serverQueue.songs.shift(); play(guild, serverQueue.songs[0]); }) .on("error", error => console.error(error)); dispatcher.setVolumeLogarithmic(serverQueue.volume / 5); serverQueue.textChannel.send(`Start playing: **${song.title}**`); }
额外注意点
- 如果你使用的是discord.js v14及以上版本,语音相关功能已经拆分到
@discordjs/voice包,voiceChannel.join()、connection.play()的API已经发生变化,需要适配新的语音API写法。 - ytdl需要安装最新版本,否则可能出现无法拉取音频流的问题。
内容的提问来源于stack exchange,提问作者Ross Beckett
相关产品推荐
相关产品推荐

