Discord.js如何回溯获取用户的最后活动信息?
获取Discord用户最后活动时间的可行方案
你提到的member.user.lastMessage确实有局限性——它只存储你的Discord.js客户端启动后收到的用户消息,所以如果用户在客户端启动前发过消息或者离线后没再发,就会返回null。下面是几种实用的替代方案:
1. 利用用户的Presence状态
Discord的Presence系统能提供用户的在线状态及相关时间线索:
- 对于在线/Idle/Do Not Disturb状态的用户,
member.presence会包含当前的活动信息(比如正在玩的游戏、流媒体内容),虽然没有直接的"最后活动时间"字段,但能判断用户当前是否活跃。 - 对于离线用户,
member.presence.lastStatusAt可以获取他们最后一次切换到离线状态的时间(注意:如果用户一直处于离线状态,这个字段可能不存在)。
示例代码:
client.guilds.cache.get('SERVER ID').members.fetch().then(members => { const role = members.roles.cache.find(r => r.name === 'Newbies'); role.members.forEach(member => { if (member.presence.status === 'offline' && member.presence.lastStatusAt) { console.log(`${member.user.tag} 最后离线时间:${member.presence.lastStatusAt}`); } else if (member.presence.status !== 'offline') { const activities = member.presence.activities.map(a => a.name).join(', '); console.log(`${member.user.tag} 当前在线,活动:${activities || '无'}`); } }); });
2. 回溯服务器频道的消息历史
如果你的机器人拥有读取消息历史权限,可以遍历服务器内的文本频道,查找用户的最后一条消息。这种方法能拿到用户在服务器内的最后发言时间,但在大服务器里效率较低,建议限制频道范围或消息数量:
示例代码:
async function getLastMessageTime(member) { let lastMessageTime = null; // 筛选服务器内的文本频道 const textChannels = member.guild.channels.cache.filter(c => c.type === 'GUILD_TEXT'); for (const channel of textChannels.values()) { try { // 获取频道内最近100条消息(Discord API单次最多返回100条) const messages = await channel.messages.fetch({ limit: 100 }); // 筛选该用户的消息 const userMessages = messages.filter(m => m.author.id === member.user.id); if (userMessages.size > 0) { const latestMsg = userMessages.sort((a, b) => b.createdTimestamp - a.createdTimestamp).first(); if (!lastMessageTime || latestMsg.createdTimestamp > lastMessageTime) { lastMessageTime = latestMsg.createdTimestamp; } } } catch (err) { console.error(`无法读取频道 ${channel.name} 的消息历史:${err}`); } } return lastMessageTime ? new Date(lastMessageTime) : null; } // 使用示例 client.guilds.cache.get('SERVER ID').members.fetch().then(async members => { const role = members.roles.cache.find(r => r.name === 'Newbies'); for (const member of role.members.values()) { const lastActive = await getLastMessageTime(member); console.log(`${member.user.tag} 最后发言时间:${lastActive || '未找到历史消息'}`); } });
3. 自行记录用户活动
如果需要长期稳定追踪用户最后活动,最可靠的方法是在机器人启动后,实时监听用户的消息、状态更新等事件,并将活动时间存储到数据库(比如SQLite、MongoDB)。这样无论机器人重启多少次,都能获取到完整的历史活动记录:
示例代码(使用SQLite,需先安装sqlite3包):
const sqlite3 = require('sqlite3').verbose(); const db = new sqlite3.Database('./user_activity.db'); // 创建用户活动记录表 db.run(`CREATE TABLE IF NOT EXISTS user_activity ( user_id TEXT PRIMARY KEY, last_active INTEGER )`); // 监听消息事件,更新最后活动时间 client.on('messageCreate', message => { if (!message.author.bot) { db.run(`REPLACE INTO user_activity (user_id, last_active) VALUES (?, ?)`, [message.author.id, Date.now()]); } }); // 监听用户状态更新事件 client.on('presenceUpdate', (oldPresence, newPresence) => { if (!newPresence.user.bot) { db.run(`REPLACE INTO user_activity (user_id, last_active) VALUES (?, ?)`, [newPresence.user.id, Date.now()]); } }); // 从数据库查询用户最后活动时间 function getLastActiveFromDB(userId) { return new Promise((resolve, reject) => { db.get(`SELECT last_active FROM user_activity WHERE user_id = ?`, [userId], (err, row) => { if (err) reject(err); resolve(row ? new Date(row.last_active) : null); }); }); } // 使用示例 client.guilds.cache.get('SERVER ID').members.fetch().then(async members => { const role = members.roles.cache.find(r => r.name === 'Newbies'); for (const member of role.members.values()) { const lastActive = await getLastActiveFromDB(member.user.id); console.log(`${member.user.tag} 最后活动时间:${lastActive || '无记录'}`); } });
注意事项
- Discord API本身没有提供直接获取用户"最后活动时间"的端点,所有方案都是基于现有数据的间接实现。
- 消息历史查询受限于机器人的权限和Discord的消息保留规则(默认保留30天,除非开启永久保留)。
- Presence状态的
lastStatusAt字段可能存在延迟,尤其是用户长时间离线时,数据可能不准确。
内容的提问来源于stack exchange,提问作者owenmelbz
相关产品推荐
相关产品推荐

