Discord.js v14:Express请求超时及Embed无法更新问题求助
问题分析与解决方案
一、Redis缓存未生效的原因及修复
你的Redis缓存完全没起作用,核心错误有两个:
- Redis客户端未建立连接:Redis v4+版本要求显式调用
connect()方法初始化连接,否则所有缓存操作都会静默失败。 - 缓存写入对象错误:代码中
client.setex(...)的client是Discord机器人客户端实例,并非Redis客户端,导致缓存根本无法写入。
修复代码:
// 初始化Redis客户端并添加连接逻辑 const redClient = redis.createClient(); redClient.on('error', err => console.log('Redis Client Error', err)); redClient.connect().then(() => console.log('Redis连接成功')); // 在app.get('/')接口中修正缓存写入代码: // 原错误代码:client.setex(key, 3600, JSON.stringify(toBan[0])); // 改为: await redClient.setEx(key, 3600, JSON.stringify(toBan[0]));
二、请求响应时长过长(2分钟)的原因及优化
- 全局数组的竞态问题:使用全局
toBan数组存储待处理任务,当多个请求并发时,toBan.shift()会导致任务错乱,第三方服务可能长时间等待不到对应数据。 - Redis缓存失效:修复上述Redis问题后,重复请求会直接命中缓存,大幅缩短响应时间。
- Discord消息重复拉取:每次缓存未命中时都要重新拉取Discord消息,可在任务创建时就将数据存入Redis,避免重复操作。
优化建议:
在byUser/byUID成功获取用户信息后,直接将任务数据存入Redis,减少后续接口的依赖:
// 在byUser的res.on('end')成功分支中: const taskData = {method: method,value: JSON.parse(data).Id,username: JSON.parse(data).Username,cid: message.channel.id,mid: message.id}; const key = `${message.channel.id}_${message.id}`; await redClient.setEx(key, 3600, JSON.stringify(taskData)); toBan.push(taskData); // 保留数组兼容现有逻辑,后续可完全替换为Redis // byUID的成功分支做同样修改
三、Embed消息无法随流程更新的原因及修复
当前流程仅在任务开始时更新Embed为"Attempting...",后续只有等第三方服务回调才更新最终状态,中间没有任何反馈,导致用户看不到流程进展。
修复步骤:
- 在Roblox API请求成功后更新Embed状态:
// 修改byUser中的res.on('end')成功分支: if (JSON.parse(data).Id != undefined) { console.log("push") const taskData = {method: method,value: JSON.parse(data).Id,username: JSON.parse(data).Username,cid: message.channel.id,mid: message.id}; toBan.push(taskData); // 添加等待处理状态的Embed更新 const waitingEmb = new EmbedBuilder() .setColor('#0099ff') .setDescription(`已获取用户信息,等待${method}处理...`) .addFields( {name: 'Username', value: JSON.parse(data).Username}, {name: 'UserID', value: JSON.parse(data).Id} ) .setTimestamp() .setFooter(footer); message.edit({ embeds: [waitingEmb] }); }
- 简化第三方回调时的Embed更新逻辑:去掉
msg.author != undefined的冗余判断,直接编辑消息,若消息已删除则发送新消息:
// 原代码: if (msg.author != undefined) { msg.edit({ embeds: [Emb] }); } else { channel.send({ embeds: [Emb] }); } // 改为: msg.edit({ embeds: [Emb] }).catch(err => { channel.send({ embeds: [Emb] }); });
其他细节优化
将回调式的https.get封装为Promise,避免回调地狱,提升代码可读性:
const fetchRobloxUser = (url) => { return new Promise((resolve, reject) => { https.get(url, (res) => { let data = ''; res.on('data', d => data += d); res.on('end', () => { res.statusCode === 200 ? resolve(JSON.parse(data)) : reject(new Error(`API请求失败,状态码:${res.statusCode}`)); }); }).on('error', reject); }); }; // 重构byUser函数为异步函数: async function byUser(method,usr,message) { const emb = new EmbedBuilder() .setColor('#fff200') .setDescription(`尝试${method}用户:${usr}...`) .setTimestamp() .setFooter(footer); await message.edit({ embeds: [emb] }); try { const userData = await fetchRobloxUser(`https://api.roblox.com/users/get-by-username?username=${usr}`); if (userData.Id) { const taskData = {method, value: userData.Id, username: userData.Username, cid: message.channel.id, mid: message.id}; toBan.push(taskData); const waitingEmb = new EmbedBuilder() .setColor('#0099ff') .setDescription(`已获取用户信息,等待${method}处理...`) .addFields( {name: 'Username', value: userData.Username}, {name: 'UserID', value: userData.Id} ) .setTimestamp() .setFooter(footer); await message.edit({ embeds: [waitingEmb] }); } else { await message.edit({ embeds: [Invalid] }); } } catch (error) { console.error("RBLX API(用户名查询)| " + error); await message.edit({ embeds: [Invalid] }); } }
内容的提问来源于stack exchange,提问作者Eli
相关产品推荐
相关产品推荐

