NodeJS重启后如何持久化变量?解决JSON循环结构序列化报错
解决Node.js中循环引用对象无法保存到文件的问题
问题根源
你遇到的TypeError: Converting circular structure to JSON错误,是因为Discord的Message对象包含循环引用(比如对象内部的client属性指向Discord客户端实例,而客户端实例又通过事件引用回消息相关对象),而JSON.stringify本身无法处理这种闭环引用。另外,代码里的await JSON.stringify(newmsg)是多余的——JSON.stringify是同步函数,不需要用await修饰。
解决方案
1. 只保存必要数据(推荐)
不需要保存整个Message对象,里面大部分是Discord客户端的内部引用,重启后完全没用。只提取重启后恢复消息需要的核心字段即可:
// 发送消息并提取关键数据 const newmsg = await message.channel.sendMessage("world"); const msgData = { id: newmsg.id, channelId: newmsg.channel.id, content: newmsg.content, createdAt: newmsg.createdAt.toISOString(), authorId: newmsg.author.id }; // 用Promise版fs写入文件(贴合async/await语法) const fs = require('fs').promises; try { await fs.writeFile('msg.json', JSON.stringify(msgData, null, 2)); console.log('JSON data is saved.'); } catch (err) { console.error('保存失败:', err); }
2. 处理循环引用(仅需保存更多字段时使用)
如果必须保留更多Message对象的字段,可以自定义replacer函数,在JSON序列化时忽略会导致循环引用的内部属性:
const newmsg = await message.channel.sendMessage("world"); const fs = require('fs').promises; // 自定义replacer,过滤循环引用属性 function jsonReplacer(key, value) { // 忽略Discord客户端、事件等内部引用 if (['client', '_events', 'context', 'guild'].includes(key)) { return undefined; } return value; } try { const data = JSON.stringify(newmsg, jsonReplacer, 2); await fs.writeFile('msg.json', data); console.log('JSON data is saved.'); } catch (err) { console.error('保存失败:', err); }
注意:这种方式保存的对象无法还原成完整的Message实例,只能拿到静态数据,因此更推荐第一种方案。
3. 重启后恢复消息
读取保存的文件,通过Discord客户端重新获取或重建消息:
const fs = require('fs').promises; async function restoreSavedMessage(client) { try { const rawData = await fs.readFile('msg.json', 'utf8'); const msgData = JSON.parse(rawData); // 获取目标频道 const channel = await client.channels.fetch(msgData.channelId); if (!channel) { console.error('频道不存在'); return null; } // 尝试获取原消息(如果消息未被删除) try { const savedMsg = await channel.messages.fetch(msgData.id); console.log('已恢复原消息'); return savedMsg; } catch (err) { // 原消息不存在时,用保存的内容重新发送 const newMsg = await channel.send(`[恢复的消息] ${msgData.content}`); console.log('已重新发送消息'); return newMsg; } } catch (err) { console.error('恢复失败:', err); return null; } } // 在客户端ready事件中调用 client.on('ready', async () => { await restoreSavedMessage(client); });
内容的提问来源于stack exchange,提问作者user3789797
相关产品推荐
相关产品推荐

