Webhooks 詳解:簽章載荷與重試機制

Backend2026-09-18TryQuickToolBox

你剛剛整合了支付閘道或 CI/CD 服務,現在需要接收即時事件。Webhooks 是標準解決方案,但伴隨著一些陷阱:未經驗證的載荷、遺失的事件以及重複傳遞。本文將說明 webhooks 的運作方式、如何簽署載荷以防止竄改,以及如何實作重試以確保可靠傳遞。

什麼是 Webhooks?

Webhook 是一種使用者定義的 HTTP 回呼。每當事件發生時,提供者會向你指定的 URL 發送 HTTP POST 請求,而不是讓你的應用程式輪詢 API 來取得更新。這種方式更有效率,並能實現近乎即時的反應。

常見的使用案例包括:

為什麼要簽署 Webhook 載荷?

Webhook 端點是公開可存取的 URL。若未經驗證,任何人都可以發送偽造的載荷,導致資料損毀或安全漏洞。使用共享密鑰簽署載荷可確保真實性和完整性。

大多數提供者使用 HMAC(雜湊訊息鑑別碼)搭配 SHA-256。提供者使用密鑰對原始請求主體計算簽章,並將其包含在標頭中(例如 X-Hub-Signature-256)。你的伺服器重新計算簽章並進行比對。

如何驗證簽章

以下是逐步指南:

  1. 取得原始主體,完全按照發送的內容。在驗證前請勿解析或修改它。
  2. 從標頭中提取簽章。
  3. 使用你的密鑰和 HMAC-SHA256 計算預期簽章。
  4. 使用恆定時間函式進行比較,以防止計時攻擊。

Node.js 範例:

const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const digest = 'sha256=' + hmac.update(payload).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(signature));
}

Python 範例:

import hmac
import hashlib

def verify_signature(payload, signature, secret):
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f'sha256={expected}', signature)

始終使用恆定時間比較,以避免洩漏資訊。

實作重試以確保可靠性

網路會故障、伺服器會重新啟動,部署也會發生。一個穩健的 webhook 系統必須重試失敗的傳遞。提供者通常會使用指數退避進行重試,但你也應該在接收端處理重試。

重試策略

冪等鍵

許多提供者會包含唯一的事件 ID(例如 X-Event-ID)。將已處理的 ID 儲存在資料庫或快取中,以跳過重複項。例如,使用 Redis 搭配 TTL 來追蹤已見過的 ID。

比較:輪詢 vs Webhooks

面向 輪詢 Webhooks
延遲 取決於間隔 近乎即時
伺服器負載 高(持續請求) 低(僅在事件發生時)
複雜度 易於實作 需要端點、安全性、重試
可靠性 可能遺漏輪詢之間的事件 若端點離線可能遺漏;重試有助於改善

Webhook 消費者的最佳實踐

常見問題

什麼是 webhook 簽章?

Webhook 簽章是使用共享密鑰建立的載荷 HMAC 雜湊。它允許接收方驗證請求來自預期的發送方,且未被竄改。

我應該重試失敗的 webhook 多少次?

沒有通用的數字,但使用指數退避進行 3–5 次重試是常見做法。之後,將事件記錄到死信佇列以供手動審查。

我可以不使用 HTTPS 來使用 webhooks 嗎?

技術上可以,但非常不安全。始終使用 HTTPS 來加密載荷並防止中間人攻擊。

準備好測試你的 webhook 端點了嗎?使用我們的 JSON Formatter 快速檢查和驗證載荷。