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

Discord DM频道创建失败:连接超时与HTTP 500错误求助

问题描述

已更新Discord机器人token,尝试过不同账号的用户ID,但调用接口时仍返回HTTP 500状态码,网络环境正常。以下是我开发的Discord机器人代码,求解决方法:

DiscordClient 实现代码
import { REST } from "@discordjs/rest";
import { 
    Routes,
    APIEmbed,
    RESTPostAPIChannelMessageResult,
    RESTPostAPICurrentUserCreateDMChannelResult,
 } from "discord-api-types/v10";

 export class DiscordClient {
    private rest: REST
  
    constructor(token: string | undefined) {
      if (!token) {
        throw new Error('Discord token is required');
      }

      this.rest = new REST({ version: "10",timeout:60000 }).setToken(token ?? "")
    }
  
    async createDM(
      userId: string
    ): Promise<RESTPostAPICurrentUserCreateDMChannelResult> {
        try {
            const response = await this.rest.post(Routes.userChannels(), {
              body: { recipient_id: userId },
            });
            return response as RESTPostAPICurrentUserCreateDMChannelResult;
           } catch (error) {
            console.error(error);
            throw new Error('Failed to create Discord DM channel');
          }
    }
  
    async sendEmbed(
      channelId: string,
      embed: APIEmbed
    ): Promise<RESTPostAPIChannelMessageResult> {
      return this.rest.post(Routes.channelMessages(channelId), {
        body: { embeds: [embed] },
      }) as Promise<RESTPostAPIChannelMessageResult>
    }
}
业务逻辑处理代码
import { FREE_QUOTA, PRO_QUOTA } from "@/config";
import { db } from "@/db";
import { DiscordClient } from "@/lib/discord-client";
import { CATEGORY_NAME } from "@/lib/validators/category-validator";
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";

const REQUEST_VALIDATOR = z.object({
    category:CATEGORY_NAME,
    fields:z.record(z.string().or(z.number()).or(z.boolean())).optional(),
    description:z.string().optional()
}).strict()

export const POST = async (req:NextRequest) => {
    const authHeader = req.headers.get('Authorization');

    if(!authHeader) { 
        return NextResponse.json({ message: "Unauthorized" },{ status:401 })
    }

    if(!authHeader.startsWith('Bearer ')) {
        return NextResponse.json({
            message:"Invalid auth header format. Expected:'Bearer [<API_KEY>]'"
        },{ status:401 })
    }

    const apiKey = authHeader.split(' ')[1]

    if(!apiKey || apiKey.trim() === '') {
        return NextResponse.json({
            message:"Invalid API Key"
        },{ status:401 })

    }

    const user = await db.user.findUnique({
        where:{ apiKey },
        include:{ EventCategories:true }
    })

    if(!user) {
        return NextResponse.json({
            message:"Invalid API Key"
        },{ status:401 })
    }

    if(!user.discordId) {
        return NextResponse.json({
            message:"Please enter your discord id in your account settings"
        },{ status:403 })

    }

    //时间
    const currentData = new Date();
    const currentMonth = currentData.getMonth() + 1;
    const currentYear = currentData.getFullYear();

    const quota = await db.quota.findUnique({
        where:{
            userId:user.id,
            month:currentMonth,
            year:currentYear
        }
    })

    const quotaLimit = user.plan === "FREE" ? FREE_QUOTA.maxEventsPerMonth : PRO_QUOTA.maxEventsPerMonth;

    if(quota && quota.count >= quotaLimit){
        return NextResponse.json({
            message:"Please upgrade your plan to create more events"
        },{ status:429 })
    }

    const discord = new DiscordClient(process.env.DISCORD_BOT_TOKEN)


    const dmChannel = await discord.createDM(user.discordId)

    console.log(dmChannel)

    let requestData:unknown;

    try {
        requestData = await req.json();
    } catch (error) {
        console.log(error)
        
        return NextResponse.json({
            message:"Invalid request body"
        },{ status:400 })
    }

    const validationResult = REQUEST_VALIDATOR.parse(requestData);

    const category = user.EventCategories.find(
        (category) => category.name === validationResult.category
    )

    if(!category) {
        return NextResponse.json({
            message:`You don't have a category with that name '${validationResult.category}'`
        },{ status:400 })
    }   

    const dataList = {
        title:`${category.emoji || "🤖"} ${category.name.charAt(0).toUpperCase() + category.name.slice(1)}`,
        description:validationResult.description || `A new ${category.name} event has been created!`,
        color:category.color,
        time:new Date().toISOString(),
        fields:Object.entries(validationResult.fields || {}).map(
            ([key,value]) => {
                return {
                    name:key,
                    value:value.toString(),
                    inline:true
                }
            }
        )
    }

    const event = await db.event.create({
        data:{
            name:category.name,
            userId:user.id,
            eventCategoryId:category.id,
            fields:validationResult.fields || {},
            formattedMessage:`${dataList.title}\n\n${dataList.description}`
        }
    })

    try {
        await discord.sendEmbed(dmChannel.id,dataList)

        await db.event.update({
            where:{
                id:event.id
            },
            data:{
                DeliveryStatus:"DELIVERED"
            }
        })

        await db.quota.upsert({
            where:{
                userId:user.id,
                month:currentMonth,
                year:currentYear
            },
            update:{
                count:{
                    increment:1

                }
            },
            create:{
                userId:user.id,
                month:currentMonth,
                year:currentYear,
                count:1
            }
        })
    } catch (err) {
        await db.event.update({
            where:{
                id:event.id
            },
            data:{
                DeliveryStatus:"FAILED"
            }
        })

        console.log(err)

        return NextResponse.json({
            message:"Error processing event",
            eventId:event.id
        },{
            status:500
        })
    }

    return NextResponse.json({
        message:"Event created successfully",
        eventId:event.id
    })
}
解决建议
  • 检查用户与机器人的关联:Discord机器人无法给和自己没有共同服务器的用户创建DM,确认目标用户和机器人至少在一个共同服务器中,且机器人在该服务器拥有SendMessages权限。
  • 细化错误日志:当前createDM和sendEmbed的错误处理过于笼统,无法获取Discord返回的具体错误信息。修改catch块,打印完整的API错误响应:
    // 以createDM为例
    catch (error: any) {
      const errorDetails = error.response?.data || error.message;
      console.error('Discord API 创建DM失败:', errorDetails);
      throw new Error(`创建DM失败: ${errorDetails.message || errorDetails}`);
    }
    
    这样能明确是权限问题、用户不存在还是其他API限制导致的错误。
  • 校验Embed格式:Discord的Embed字段有严格限制:
    • color必须是十进制整数(如果存储的是十六进制字符串,需要转换:Number(0x${category.color.slice(1)}))
    • title长度不能超过256字符,description不能超过4096字符
    • 每个field的name不能超过256字符,value不能超过1024字符,最多25个fields
  • 验证Token有效性:用curl直接测试token是否有效:
    curl -H "Authorization: Bot YOUR_BOT_TOKEN" https://discord.com/api/v10/users/@me
    
    如果返回机器人用户信息,说明token正常;否则检查token是否正确、机器人账号是否被封禁。
  • 调整异步流程顺序:当前代码先调用Discord API创建DM,再处理请求体校验,建议先完成请求体解析和业务校验,再调用Discord API,避免不必要的无效请求。

内容的提问来源于stack exchange,提问作者宇文所拓

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:24:51