You need to enable JavaScript to run this app. Discord.js机器人JSON读写实现与writerrp指令报错修复
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js机器人JSON读写实现与writerrp指令报错修复

Discord.js JSON 读写功能问题修复

原有代码的报错触发点

  • 直接将Discord的GuildMember类对象塞进待序列化的JSON内容中,这类对象自带循环引用,会直接抛出Converting circular structure to JSON类型错误
  • 写文件逻辑使用覆盖式写入,每次触发指令都会把之前存储的所有记录全部清掉,无法实现多用户、多条证据的存储需求
  • 缺少前置判断中断逻辑:当用户没@人、没填证据链接时,只发送了提示消息但没有终止后续执行流程,会把undefined值直接写入JSON
  • 非固定的相对路径引用,文件结构调整后很容易触发文件权限、路径不存在的报错
  • 异步写文件没有等待完成就执行冷却逻辑,存在时序不一致的问题

修复后的写入指令(对应writerrp需求)

const Discord = require("discord.js")
const fs = require("fs");
const path = require("path");
const botconfig = require("../botconfig.json");
const colours = require("../colours.json");
const superagent = require("superagent");
const usedCommand = new Set();

module.exports.run = async (bot, message, args) => {
    await message.delete();
    // 指令冷却校验
    if (usedCommand.has(message.author.id)) {
        return message.reply("du kannst diesen Command erst in 15 Sekunden wieder verwenden.")
            .then(msg => msg.delete({ timeout: 10000 }));
    }

    // 参数有效性校验
    let member = message.mentions.members.first() || message.guild.members.cache.get(args[0]);
    if (!member) {
        return message.reply("Bitte markiere einen gültigen Benutzer, für den du den Beweis speichern willst!")
            .then(msg => msg.delete({ timeout: 10000 }));
    }

    let reason = args.slice(1).join(" ").trim();
    if (!reason) {
        return message.reply("Bitte gebe einen Beweis in Form von einem Link (Video: Youtube, Bild: prnt.sc) an!")
            .then(msg => msg.delete({ timeout: 10000 }));
    }

    // 定位存储文件路径,避免相对路径偏差
    const rppFilePath = path.resolve(__dirname, "../rpp.json");
    let storedProofs = [];
    // 读取原有存储内容
    try {
        if (fs.existsSync(rppFilePath)) {
            storedProofs = JSON.parse(fs.readFileSync(rppFilePath, "utf8"));
        }
    } catch (err) {
        console.error("Lese-Fehler rpp.json:", err);
        return message.reply("Fehler beim Laden der gespeicherten Beweise!")
            .then(msg => msg.delete({ timeout: 10000 }));
    }

    // 构造可序列化的存储条目,仅保留核心信息
    const newRecord = {
        targetUserId: member.id,
        targetUsername: member.user.tag,
        proofLink: reason,
        submitter: message.author.tag,
        submitTime: Date.now()
    };
    storedProofs.push(newRecord);

    // 写回更新后的内容到文件
    try {
        fs.writeFileSync(rppFilePath, JSON.stringify(storedProofs, null, 4), "utf8");
    } catch (err) {
        console.error("Schreib-Fehler rpp.json:", err);
        return message.reply("Fehler beim Speichern des Beweises!")
            .then(msg => msg.delete({ timeout: 10000 }));
    }

    // 触发冷却计时
    usedCommand.add(message.author.id);
    setTimeout(() => usedCommand.delete(message.author.id), 15000);

    message.reply(`Beweis für ${member.user.tag} wurde erfolgreich gespeichert!`)
        .then(msg => msg.delete({ timeout: 10000 }));
}

module.exports.config = {
    name: "writerrp",
    description: "Speichert Beweise zu markierten Nutzern in der lokalen JSON-Datei",
    usage: "+writerrp @[Nutzer] [Beweis-Link]",
    accessableby: "Members",
    aliases: ["proofwrite", "rpp"]
}

配套readrrp读取指令实现

  • 功能逻辑:接收@用户或用户ID为参数,从存储文件中筛选对应用户的所有证据条目,格式化后通过嵌入消息返回
const Discord = require("discord.js")
const fs = require("fs");
const path = require("path");

module.exports.run = async (bot, message, args) => {
    await message.delete();
    // 校验查询目标
    let targetUser = message.mentions.members.first() || message.guild.members.cache.get(args[0]);
    if (!targetUser) {
        return message.reply("Bitte markiere den Nutzer, für den du gespeicherte Beweise abfragen willst!")
            .then(msg => msg.delete({ timeout: 10000 }));
    }

    // 读取存储文件
    const rppFilePath = path.resolve(__dirname, "../rpp.json");
    let storedProofs = [];
    if (fs.existsSync(rppFilePath)) {
        storedProofs = JSON.parse(fs.readFileSync(rppFilePath, "utf8"));
    }

    // 匹配对应用户的所有记录
    const matchedProofs = storedProofs.filter(item => item.targetUserId === targetUser.id);
    if (matchedProofs.length === 0) {
        return message.reply(`Es wurden keine Beweise für ${targetUser.user.tag} gefunden.`)
            .then(msg => msg.delete({ timeout: 10000 }));
    }

    // 构造展示用嵌入
    const responseEmbed = new Discord.MessageEmbed()
        .setTitle(`Gespeicherte Beweise für ${targetUser.user.tag}`)
        .setColor("#ff4444");
    matchedProofs.forEach((entry, index) => {
        responseEmbed.addField(
            `Beweis #${index + 1}`,
            `Eingereicht von ${entry.submitter} am ${new Date(entry.submitTime).toLocaleString("de-DE")}\nLink: ${entry.proofLink}`
        );
    });

    message.channel.send({ embeds: [responseEmbed] });
}

module.exports.config = {
    name: "readrrp",
    description: "Liest gespeicherte Beweise zu einem Nutzer aus der lokalen JSON-Datei",
    usage: "+readrrp @[Nutzer]",
    accessableby: "Moderatoren",
    aliases: ["proofread"]
}

开发注意点

  • 小体量的本地JSON文件读写使用同步方法即可,不会造成Bot主进程阻塞,还能避免异步时序导致的执行顺序混乱问题
  • 永远不要把Discord.js的类对象直接序列化到JSON,这类对象的内部引用结构天生不适合直接做字符串序列化
  • 文件路径统一用path.resolve拼接,适配不同操作系统的路径规则,避免硬写相对路径带来的兼容性问题

内容的提问来源于stack exchange,提问作者Beyazz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.07 23:24:03