Webhooks 詳解:簽名載荷與重試機制
您已經建立了一個 API,現在需要在事件發生時通知其他服務。您設置了一個 webhook 端點,但很快發現可靠地傳遞 HTTP 請求比看起來更困難。網路故障、惡意行為者和重複事件可能造成混亂。本指南說明如何實作帶有簽名載荷和重試的 webhooks,以便您建立穩健的整合。
什麼是 Webhooks?
Webhooks 是使用者定義的 HTTP 回呼。當您的應用程式中發生事件時,您向訂閱者提供的 URL 發送 HTTP POST 請求。這允許服務之間進行即時通訊,而無需輪詢。
例如,支付處理器可能在扣款成功時向您的應用程式發送 webhook。您的應用程式可以立即更新訂單狀態。
為什麼要簽名 Webhook 載荷?
Webhook 端點是公開可存取的,因此任何人都可以發送偽造請求。如果沒有驗證,您的應用程式可能會處理欺詐事件。簽名載荷確保請求來自您的服務且未被篡改。
簽名通常使用發送方和接收方共享的密鑰。發送方對載荷計算基於雜湊的訊息驗證碼(HMAC),並將其包含在標頭中。接收方重新計算 HMAC 並進行比較。
如何生成和驗證簽名
大多數實作使用 HMAC-SHA256。以下是一個 Python 的簡單範例:
import hmac
import hashlib
import json
def generate_signature(payload, secret):
body = json.dumps(payload, separators=(',', ':')).encode('utf-8')
signature = hmac.new(secret.encode('utf-8'), body, hashlib.sha256).hexdigest()
return signature
def verify_signature(payload, signature, secret):
expected = generate_signature(payload, secret)
return hmac.compare_digest(expected, signature)
發送 webhook 時,將簽名包含在類似 X-Signature 的標頭中。接收方提取原始主體,重新計算 HMAC 並進行比較。始終使用常數時間比較函數以防止時序攻擊。
實作重試以實現可靠傳遞
Webhooks 透過網際網路發送,因此失敗是不可避免的。您的伺服器可能宕機、網路可能緩慢,或者訂閱者可能返回錯誤。使用指數退避的重試至關重要。
重試策略
一種常見方法是使用遞增的延遲進行重試:1 分鐘、5 分鐘、30 分鐘、2 小時等。在達到最大嘗試次數(例如 10 次)或總時間窗口(例如 24 小時)後停止。
僅在特定條件下重試:網路錯誤、5xx 回應或 429(請求過多)。不要對 4xx 錯誤(429 除外)重試,因為它們表示客戶端錯誤,重試無法修復。
重試邏輯範例
以下是使用 requests 庫的 Python 簡化重試機制:
import requests
import time
from requests.exceptions import RequestException
def send_webhook(url, payload, secret, max_retries=5):
headers = {'Content-Type': 'application/json'}
signature = generate_signature(payload, secret)
headers['X-Signature'] = signature
for attempt in range(max_retries):
try:
response = requests.post(url, json=payload, headers=headers, timeout=10)
if response.status_code < 500 and response.status_code != 429:
return response.status_code
except RequestException:
pass
# 帶有抖動的指數退避
delay = (2 ** attempt) + (random.random() * 0.1)
time.sleep(delay)
return None # 重試後失敗
在生產環境中,您會將失敗的嘗試存儲在佇列中並非同步處理。Celery 或雲端佇列(AWS SQS、Google Cloud Tasks)等工具可以提供幫助。
Webhook 安全最佳實踐
- 使用 HTTPS:始終透過 TLS 發送 webhooks 以防止竊聽。
- 包含時間戳:在載荷中加入時間戳,並拒絕超過幾分鐘的請求以防止重放攻擊。
- 輪換密鑰:定期更改簽名密鑰,並在輪換期間支援多個活躍密鑰。
- 驗證 URL:註冊 webhook 時,確保 URL 可存取並對測試請求返回 2xx。
- 速率限制:透過限制每個訂閱者的請求數量,保護您的 webhook 發送方免受濫用。
處理重複和冪等性
重試可能導致重複傳遞。在載荷中包含唯一事件 ID,並讓接收方追蹤已處理的 ID。如果某個事件 ID 之前已見過,則忽略它。
或者,將事件處理常式設計為冪等。例如,多次使用相同資料更新記錄應與執行一次具有相同的效果。
測試 Webhooks
使用 ngrok 等工具暴露您的本機伺服器並測試 webhook 傳遞。透過返回錯誤碼模擬失敗,並驗證重試是否按預期發生。
常見問題
什麼是簽名 webhook 載荷?
簽名載荷包含加密簽名(通常是 HMAC),允許接收方驗證請求來自受信任的來源且未被修改。
我應該重試失敗的 webhook 多少次?
這取決於您的可靠性需求。常見做法是在 24 小時內使用指數退避重試 5-10 次。始終允許訂閱者手動觸發重試。
我可以不使用簽名嗎?
可以,但有風險。沒有簽名,任何人都可以發送偽造事件。在生產環境中始終簽名 webhooks 以防止欺詐。
準備好測試您的 webhook 載荷了嗎?在發送之前,使用我們的 JSON Formatter 驗證和美化 JSON 載荷。