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错误响应:
这样能明确是权限问题、用户不存在还是其他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}`); } - 校验Embed格式:Discord的Embed字段有严格限制:
color必须是十进制整数(如果存储的是十六进制字符串,需要转换:Number(0x${category.color.slice(1)}))title长度不能超过256字符,description不能超过4096字符- 每个field的
name不能超过256字符,value不能超过1024字符,最多25个fields
- 验证Token有效性:用curl直接测试token是否有效:
如果返回机器人用户信息,说明token正常;否则检查token是否正确、机器人账号是否被封禁。curl -H "Authorization: Bot YOUR_BOT_TOKEN" https://discord.com/api/v10/users/@me - 调整异步流程顺序:当前代码先调用Discord API创建DM,再处理请求体校验,建议先完成请求体解析和业务校验,再调用Discord API,避免不必要的无效请求。
内容的提问来源于stack exchange,提问作者宇文所拓
相关产品推荐
相关产品推荐

