投递行为
取自该平台的官方文档,最近核对于 2026-08-06。平台没有给出数字的地方,这张表也不填。
| 响应时限 | 10 秒 |
|---|---|
| 重试 | 无。GitHub 不会自动重新传递投递失败的 Webhook |
| 放弃 | 不会停用。投递在 3 天内都可以手动重新传递,之后记录不再保留 |
| 出处 | https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks |
签名
用一个经测试套件证明的可运行验证器核对,不是照着文档读来的。最近核对于 2026-08-20。
| 算法 | HMAC-SHA256 |
|---|---|
| 待签名串 | raw body |
| 编码 | hex |
| 请求头 | x-hub-signature-256 = sha256=hex |
| 时间容差 | 无强制要求 |
验证签名
要用原始请求体,逐字节一致,并且在任何 JSON 解析之前。框架一旦重新序列化请求体,本页的每一种方案都会失效。
const crypto = require("node:crypto");
// x-hub-signature-256: "sha256=" + hex(HMAC-SHA256(secret, raw body))
const expected =
"sha256=" +
crypto.createHmac("sha256", webhookSecret).update(rawBody).digest("hex");
const received = Buffer.from(req.headers["x-hub-signature-256"] ?? "");
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);容易踩的坑
你只有一次尝试。这张列表上的其他发送方都会自己重试;GitHub 不会,所以一个 30 秒的部署窗口就会丢事件,而且没有第二次机会。重新传递按钮(以及 Redelivery API)都是按单次投递手动操作的,只在 3 天内有效;之后连记录本身都没了。
延伸阅读
AnyHook 挡在接收 GitHub Webhook 的端点前面:约 1 秒应答,你的服务器宕机时按自己的计划重试,并且每个事件都可以重放。 只改一个 URL,代码不用动。