Webhook 解析:簽名負載與重試策略

Backend2026-11-10TryQuickToolBox

為何 Webhook 會失敗以及如何修復

您剛剛整合了支付供應商的 Webhook,以便在應用程式中更新訂單狀態。在測試環境中一切正常,但在生產環境中,有些事件永遠不會到達,或者更糟的是,您會收到重複的事件。如果沒有適當的防護措施,Webhook 可能會成為無聲失敗和安全漏洞的來源。

Webhook 是由事件觸發的 HTTP 回呼,但與典型的 API 呼叫不同,它們是基於推送且非同步的。這帶來了兩個核心挑戰:驗證真實性和確保傳遞。在本指南中,我們將透過簽名負載和智慧重試來解決這兩個問題。

什麼是 Webhook?

Webhook 是一種使用者定義的 HTTP 回呼。當來源系統中發生事件(例如新的付款)時,它會向您提供的 URL 發送一個包含事件資料的 HTTP POST 請求。這允許即時反應,而無需輪詢。

常見的使用案例包括付款通知、CI/CD 觸發和聊天整合。但由於 Webhook 穿越公共網際網路,它們容易受到欺騙和遺失的影響。

使用簽名負載保護 Webhook

您如何知道 Webhook 真正來自您的供應商?使用共享密鑰對負載進行簽名可確保完整性和真實性。

HMAC 簽章如何運作

供應商使用密鑰計算請求主體的 HMAC(例如 SHA-256),並在標頭中發送簽章(例如 X-Signature)。您的伺服器重新計算 HMAC 並使用常數時間比較來進行比對,以防止時序攻擊。

// Node.js 範例:驗證 Webhook 簽章
const crypto = require('crypto');

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

最佳實踐:

實作可靠的重試

即使有簽章,網路問題或停機也可能導致 Webhook 傳遞失敗。供應商通常會使用指數退避進行重試,但您也必須在您這邊處理重試。

冪等性:安全重試的關鍵

重試可能導致重複處理。使用冪等鍵(通常包含在負載中或作為標頭)來確保每個事件僅被處理一次。儲存已處理的事件 ID 並忽略重複項。

// 範例:冪等的 Webhook 處理常式
const processedEvents = new Set();

app.post('/webhook', (req, res) => {
  const eventId = req.body.id;
  if (processedEvents.has(eventId)) {
    return res.status(200).send('Already processed');
  }
  // 處理事件...
  processedEvents.add(eventId);
  res.status(200).send('OK');
});

接收端的重試策略

如果您的處理失敗,請回應 5xx 狀態碼以觸發供應商的重試。對於暫時性錯誤,您也可以實作自己的重試佇列並搭配退避。

情境回應動作
成功200 OK不重試
驗證錯誤400 Bad Request不重試(修正負載)
伺服器錯誤500 Internal Server Error供應商重試
速率限制429 Too Many Requests供應商延遲後重試

監控與除錯 Webhook

記錄所有傳入的 Webhook 請求,包括標頭和負載(遮蔽敏感資料)。使用像 JSON Formatter 這樣的工具來美化輸出負載,以便更容易檢查。設定失敗傳遞的警報並追蹤重試次數。

常見問題

什麼是簽名的 Webhook 負載?

簽名負載包含一個加密簽章(通常是 HMAC),用於驗證請求來自可信來源且未被篡改。

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

大多數供應商會使用指數退避重試 3–5 次。作為接收方,請回應適當的狀態碼,並讓供應商處理重試。

我可以不使用 HTTPS 使用 Webhook 嗎?

不可以——HTTPS 對於加密負載和防止中間人攻擊至關重要。切勿透過純 HTTP 接受 Webhook。

準備好檢查和除錯 Webhook 負載了嗎?試試我們免費的 JSON Formatter,立即格式化和驗證 JSON 資料。