Slack 如何投递 Webhook

Slack 要求在 3 秒内返回 2xx,重试 3 次,一小时内超过 95% 的投递尝试失败就停用事件订阅。附签名格式和 Node 验证器。

投递行为

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

响应时限3 秒

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

重试重试 3 次:立即、1 分钟后、5 分钟后
放弃60 分钟内超过 95% 的投递尝试失败时,事件订阅会被停用
出处https://docs.slack.dev/apis/events-api/

签名

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

算法HMAC-SHA256
待签名串v0:{timestamp}:{body}
编码hex
请求头x-slack-signature = v0=hex
时间容差5 分钟

验证签名

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

const crypto = require("node:crypto");

const ts = req.headers["x-slack-request-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) throw new Error("stale");

const expected =
  "v0=" +
  crypto
    .createHmac("sha256", signingSecret) // Slack App → Basic Information
    .update(`v0:${ts}:${rawBody}`)
    .digest("hex");
const received = Buffer.from(req.headers["x-slack-signature"] ?? "");
const wanted = Buffer.from(expected);
// timingSafeEqual throws on a length mismatch, so check that first.
const valid =
  received.length === wanted.length && crypto.timingSafeEqual(received, wanted);

容易踩的坑

三秒是所有主流发送方里最紧的时限,而且三次重试都落在五分钟之内。一个只是变慢、并没有宕机的处理程序,四次尝试会在同一次事故里全部失败。

停用规则看的是比例,不是次数:60 分钟内超过 95% 的投递尝试失败,整个应用的事件订阅就会被关闭,你的用户会眼看着机器人在频道里沉默下来。

延伸阅读

AnyHook 挡在接收 Slack Webhook 的端点前面:约 1 秒应答,你的服务器宕机时按自己的计划重试,并且每个事件都可以重放。 只改一个 URL,代码不用动;要接受重试和重放,就验证 AnyHook-Signature 请求头,因为 Slack 自己的签名 5 分钟后就会过期。

工作原理 →