You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 12:50:25