Discord 如何投递 Webhook

Discord 交互请求要求在 3 秒内发出初始响应,并用 Ed25519 而不是 HMAC 签名。附核实过的格式和 Web Crypto 验证器。

投递行为

取自该平台的官方文档,最近核对于 2026-08-06。平台没有给出数字的地方,这张表也不填。

响应时限3 秒

交互端点必须在 3 秒内发出初始响应

检测你的处理程序能否及时应答

重试平台未公布
放弃平台未公布
出处https://docs.discord.com/developers/interactions/receiving-and-responding

签名

用一个经测试套件证明的可运行验证器核对,不是照着文档读来的。最近核对于 2026-08-20。

算法Ed25519
待签名串{timestamp}{body}
编码hex
请求头x-signature-ed25519 + x-signature-timestamp
时间容差无强制要求

验证签名

要用原始请求体,逐字节一致,并且在任何 JSON 解析之前。框架一旦重新序列化请求体,本页的每一种方案都会失效。

// Ed25519, not HMAC: verify with the application's public key (hex).
const hex = (s) => Uint8Array.from(s.match(/../g), (b) => parseInt(b, 16));

const key = await crypto.subtle.importKey(
  "raw",
  hex(publicKey), // Developer Portal → Application → Public Key
  { name: "Ed25519" },
  false,
  ["verify"],
);
const valid = await crypto.subtle.verify(
  "Ed25519",
  key,
  hex(req.headers["x-signature-ed25519"]),
  new TextEncoder().encode(req.headers["x-signature-timestamp"] + rawBody),
);

Discord 会主动用无效签名探测端点,如果验证通过,就拒绝这个 URL。所以一个空壳验证器过不了接入流程,而不只是过不了安全审查。

容易踩的坑

3 秒的时限针对的是初始交互响应。退路是 type 5(deferred):在时限内先应答,等实际工作完成后再发送后续消息。

延伸阅读

AnyHook 挡在接收 Discord Webhook 的端点前面:约 1 秒应答,你的服务器宕机时按自己的计划重试,并且每个事件都可以重放。 只改一个 URL,代码不用动。

工作原理 →