Webhooks 解析:簽名載荷與重試機制

Backend2026-11-03TryQuickToolBox

你剛剛整合了一個第三方支付提供商。使用者完成了一筆購買,但你的資料庫卻從未更新。為什麼?因為本應通知你應用程式的 webhook 無聲地失敗了。如果沒有正確的簽名驗證和重試邏輯,webhooks 可能會成為神秘錯誤和安全漏洞的來源。

在本文中,我們將解釋 webhooks 如何運作、為什麼必須驗證簽名載荷,以及如何設計穩健的重試機制。我們還會展示如何有效地測試和除錯 webhooks。

什麼是 Webhooks?

Webhooks 是使用者定義的 HTTP 回呼。它們允許一個系統在事件發生時將即時資料傳送給另一個系統。例如,當支付被處理時,支付提供商會向你指定的 URL 傳送一個 HTTP POST 請求,其中包含事件的詳細資訊。

與輪詢(你的應用程式反覆請求更新)不同,webhooks 會在資料可用時立即推送給你。這使得它們高效且近乎即時。

安全問題:為什麼要驗證簽名?

Webhook 端點是公開可存取的 URL。任何人都可以向它們傳送 POST 請求。如果沒有驗證,攻擊者可以偽造請求,例如在沒有實際付款的情況下將訂單標記為已付款。為了防止這種情況,提供商會用密鑰對每個載荷進行簽名。

HMAC 簽名如何運作

大多數提供商使用 HMAC(基於雜湊的訊息驗證碼)搭配 SHA-256。他們使用共享密鑰計算請求主體的雜湊,並將其包含在標頭中,例如 X-Signature。你的伺服器重新計算雜湊並與標頭進行比較。如果匹配,則請求是真實的。

以下是 Python 中的簡單範例:

import hmac
import hashlib

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

始終使用恆定時間比較函式,如 hmac.compare_digest,以避免計時攻擊。

應避免的常見錯誤

設計可靠的重試

Webhooks 透過網際網路傳送,因此失敗是不可避免的。網路中斷、伺服器重新啟動以及端點逾時。良好的 webhook 系統會使用指數退避重試失敗的傳遞。

重試通常如何運作

提供商通常會以遞增的延遲重試:1 分鐘後、5 分鐘後、30 分鐘後等,直到達到最大嘗試次數(例如 5-10 次)。如果所有重試都失敗,則該事件被標記為失敗,並可能可供手動重放。

你的端點應快速回應 2xx 狀態碼以確認收到。如果你返回非 2xx 代碼或逾時,提供商將重試。

實作冪等性

由於重試可能導致重複傳遞,你的端點必須是冪等的。使用事件 ID(包含在載荷或標頭中)來追蹤已處理的事件。在處理之前,檢查你是否已經處理過該 ID。將已處理的 ID 儲存在具有 TTL 的資料庫中。

冪等性檢查範例:

def process_event(event_id, data):
    if db.exists(f"processed:{event_id}"):
        return  # already processed
    # process data
    db.setex(f"processed:{event_id}", 86400, "1")  # expire after 24h

逐步建置 Webhook 接收器

  1. 公開 HTTPS 端點:使用 TLS 保護傳輸中的資料。
  2. 驗證簽名:以 401 拒絕簽名無效的請求。
  3. 檢查時間戳:如果提供,確保它在可接受的時間窗口內(例如 5 分鐘)。
  4. 解析載荷:驗證 JSON 結構和必要欄位。
  5. 檢查冪等性:使用事件 ID 避免重複。
  6. 非同步處理:立即回應 200,然後在背景作業中處理以避免逾時。
  7. 記錄和監控:記錄失敗並設定警報。

在本機測試 Webhooks

在開發過程中,你需要一種方式在本機機器上接收 webhooks。像 ngrok 或 localtunnel 這樣的工具會建立一個公開 URL,轉發到你的 localhost。或者,許多提供商提供 CLI 來觸發測試事件。

始終使用有效和無效的簽名測試簽名驗證。透過返回錯誤代碼並觀察提供商的重試行為來模擬重試。

比較:Webhooks 與輪詢

方面Webhooks輪詢
即時性近乎即時受間隔延遲
效率僅在事件發生時傳送資料即使沒有資料也頻繁請求
複雜性需要端點、簽名驗證、重試實作更簡單
可靠性取決於重試機制你控制排程

常見問題

什麼是簽名 webhook 載荷?

簽名載荷包含加密簽名(通常是 HMAC),允許接收方驗證請求來自預期的傳送方且未被篡改。

Webhook 應該重試多少次?

大多數提供商使用指數退避重試 5-10 次。確切次數取決於提供商的政策。你的端點應該是冪等的以處理重複。

我的 webhook 應該返回什麼 HTTP 狀態碼?

返回 2xx 狀態碼(例如 200 OK)以確認成功接收。任何其他代碼(4xx 或 5xx)表示失敗並觸發重試。

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