Kurz gesagt
Entwickeln Sie zuverlässige Webhooks mit exponentiellem Backoff-Retry (5-10 Versuche), Idempotenzschlüsseln, HMAC-Signaturprüfung und 5-Sekunden-Timeouts. Geben Sie sofort 2xx zurück und verarbeiten Sie asynchron. Die moderne PetstoreAPI implementiert Webhooks für Bestellaktualisierungen, Haustieradoptionen und Zahlungsbenachrichtigungen mit vollständiger Wiederholungslogik und Sicherheit.
Einleitung
Sie senden einen Webhook, um einen Client darüber zu informieren, dass sein Haustier adoptiert wurde. Der Server des Clients ist ausgefallen. Ihr Webhook schlägt fehl. Versuchen Sie es erneut? Wie oft? Was, wenn der Client den Webhook zweimal erhält und dem Kunden zweimal Gebühren berechnet?
Webhooks sind HTTP-Callbacks, die Ereignisse an Client-URLs senden. Sie sind theoretisch einfach, in der Praxis jedoch komplex. Netzwerke fallen aus, Server stürzen ab, und Clients haben Fehler. Produktions-Webhooks benötigen eine Wiederholungslogik, Idempotenz, Sicherheit und Überwachung.
Die moderne PetstoreAPI implementiert produktionsreife Webhooks für Bestellaktualisierungen, Haustieradoptionen und Zahlungsbenachrichtigungen. Jeder Webhook beinhaltet Wiederholungslogik, Signaturprüfung und Idempotenz.
In diesem Leitfaden erfahren Sie, wie Sie zuverlässige Webhooks mithilfe der Muster der modernen PetstoreAPI entwerfen.
Grundlagen von Webhooks
Webhooks sind HTTP-POST-Anfragen, die bei Ereignissen an vom Client bereitgestellte URLs gesendet werden.
Wie Webhooks funktionieren
1. Client registriert Webhook-URL:
POST /webhooks
{
"url": "https://client.com/webhooks/petstore",
"events": ["pet.adopted", "order.completed"]
}
2. Ereignis tritt ein (Haustier adoptiert)
3. Server sendet Webhook:
POST https://client.com/webhooks/petstore
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...
{
"event": "pet.adopted",
"data": {
"petId": "019b4132",
"userId": "user-456",
"timestamp": "2026-03-13T10:30:00Z"
}
}
4. Client antwortet:
200 OK
Das Zuverlässigkeitsproblem
Webhooks können aus vielen Gründen fehlschlagen:
- Der Client-Server ist ausgefallen
- Netzwerk-Timeout
- Client gibt 500er-Fehler zurück
- Client ist langsam (dauert 30 Sekunden)
- Client empfängt Webhook, stürzt aber vor der Verarbeitung ab
Ohne Wiederholungslogik gehen Ereignisse verloren. Ohne Idempotenz führen doppelte Webhooks zu doppelten Aktionen.
Wiederholungslogik mit exponentiellem Backoff
Fehlgeschlagene Webhooks mit zunehmenden Verzögerungen wiederholen.
Exponentielle Backoff-Strategie
Versuch 1: Sofort
Versuch 2: 1 Sekunde später
Versuch 3: 2 Sekunden später
Versuch 4: 4 Sekunden später
Versuch 5: 8 Sekunden später
Versuch 6: 16 Sekunden später
Warum exponentiell? Wenn der Client ausgefallen ist, hilft es nicht, ihn mit Wiederholungsversuchen zu bombardieren. Exponentieller Backoff gibt Zeit zur Erholung.
Implementierung
async function sendWebhook(url, payload, attempt = 1, maxAttempts = 6) {
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Signature': generateSignature(payload)
},
body: JSON.stringify(payload),
timeout: 5000 // 5 second timeout
});
if (response.ok) {
return { success: true, attempt };
}
// Retry on 5xx errors
if (response.status >= 500 && attempt < maxAttempts) {
const delay = Math.pow(2, attempt - 1) * 1000;
await sleep(delay);
return sendWebhook(url, payload, attempt + 1, maxAttempts);
}
// Don't retry 4xx errors (client error)
return { success: false, status: response.status };
} catch (error) {
// Network error or timeout - retry
if (attempt < maxAttempts) {
const delay = Math.pow(2, attempt - 1) * 1000;
await sleep(delay);
return sendWebhook(url, payload, attempt + 1, maxAttempts);
}
return { success: false, error: error.message };
}
}
Wann wiederholen?
Wiederholen bei:
- 5xx Serverfehlern (500, 502, 503, 504)
- Netzwerk-Timeouts
- Verbindungsablehnung
- DNS-Fehlern
Nicht wiederholen bei:
- 4xx Client-Fehlern (400, 401, 404) – der Client wird diese nicht beheben
- 2xx Erfolg – bereits erfolgreich
Dead Letter Queue
Nach maximalen Wiederholungsversuchen, verschieben Sie fehlgeschlagene Webhooks zur manuellen Überprüfung in eine Dead Letter Queue:
if (!result.success) {
await deadLetterQueue.add({
url,
payload,
attempts: maxAttempts,
lastError: result.error,
timestamp: new Date()
});
}
Idempotenz zur Vermeidung von Duplikaten
Clients können denselben Webhook mehrmals erhalten. Idempotenz verhindert doppelte Verarbeitung.
Idempotenzschlüssel
Fügen Sie jedem Webhook eine eindeutige ID hinzu:
{
"id": "webhook_019b4132",
"event": "pet.adopted",
"data": {...}
}
Client speichert verarbeitete IDs:
app.post('/webhooks/petstore', async (req, res) => {
const webhookId = req.body.id;
// Check if already processed
const processed = await db.webhooks.findOne({ id: webhookId });
if (processed) {
return res.status(200).json({ message: 'Already processed' });
}
// Process webhook
await processPetAdoption(req.body.data);
// Mark as processed
await db.webhooks.insert({ id: webhookId, processedAt: new Date() });
res.status(200).json({ message: 'Processed' });
});
Idempotente Operationen
Operationen idempotent gestalten:
Schlecht (nicht idempotent):
// Charging twice causes double charge
await chargeCustomer(userId, amount);
Gut (idempotent):
// Charging with idempotency key prevents double charge
await chargeCustomer(userId, amount, { idempotencyKey: webhookId });
Signaturprüfung für die Sicherheit
Überprüfen Sie, ob Webhooks von Ihrer API stammen und nicht von einem Angreifer.
HMAC-Signatur
Signatur mit gemeinsamem Geheimnis generieren:
// Server generates signature
const crypto = require('crypto');
function generateSignature(payload, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(payload));
return hmac.digest('hex');
}
// Include in header
headers['X-Webhook-Signature'] = `sha256=${generateSignature(payload, webhookSecret)}`;
Client verifiziert Signatur:
function verifySignature(payload, signature, secret) {
const expected = generateSignature(payload, secret);
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expected}`)
);
}
app.post('/webhooks/petstore', (req, res) => {
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
...
});
Zeitstempel-Validierung
Fügen Sie einen Zeitstempel hinzu, um Replay-Angriffe zu verhindern:
{
"id": "webhook_019b4132",
"timestamp": "2026-03-13T10:30:00Z",
"event": "pet.adopted",
"data": {...}
}
Alte Webhooks ablehnen:
const webhookAge = Date.now() - new Date(req.body.timestamp);
if (webhookAge > 5 * 60 * 1000) { // 5 minutes
return res.status(400).json({ error: 'Webhook too old' });
}
Timeout-Behandlung
Legen Sie aggressive Timeouts fest, um zu verhindern, dass langsame Clients Ihr System blockieren.
5-Sekunden-Timeout
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify(payload),
timeout: 5000 // 5 seconds
});
Warum 5 Sekunden? Webhooks sollten sofort zurückkehren. Wenn ein Client länger braucht, führt er synchrone Verarbeitung durch (falsches Muster).
Asynchrones Verarbeitungsmuster
Schlecht (synchron):
app.post('/webhooks/petstore', async (req, res) => {
// This takes 30 seconds - webhook will timeout
await processOrder(req.body.data);
await sendEmail(req.body.data);
await updateInventory(req.body.data);
res.status(200).json({ message: 'Processed' });
});
Gut (asynchron):
app.post('/webhooks/petstore', async (req, res) => {
// Return immediately
res.status(200).json({ message: 'Received' });
// Process asynchronously
queue.add('process-webhook', req.body);
});
Wie die moderne PetstoreAPI Webhooks implementiert
Die moderne PetstoreAPI implementiert produktionsreife Webhooks.
Webhook-Ereignisse
pet.adopted - Haustier wurde adoptiert
pet.status_changed - Status des Haustiers geändert
order.created - Bestellung erstellt
order.completed - Bestellung abgeschlossen
payment.succeeded - Zahlung erfolgreich
payment.failed - Zahlung fehlgeschlagen
Webhook-Payload
{
"id": "webhook_019b4132-70aa-764f-b315-e2803d882a24",
"event": "pet.adopted",
"timestamp": "2026-03-13T10:30:00Z",
"data": {
"petId": "019b4132-70aa-764f-b315-e2803d882a24",
"userId": "user-456",
"orderId": "order-789",
"adoptionDate": "2026-03-13"
},
"apiVersion": "v1"
}
Wiederholungskonfiguration
- Maximale Versuche: 10
- Backoff: Exponentiell (1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s)
- Gesamtes Wiederholungsfenster: ~17 Minuten
- Dead Letter Queue nach maximalen Wiederholungsversuchen
Sicherheit
- HMAC-SHA256-Signatur im
X-Webhook-Signature-Header - Zeitstempel-Validierung (Ablehnung von Webhooks, die älter als 5 Minuten sind)
- HTTPS für Webhook-URLs erforderlich
Testen von Webhooks mit Apidog
Apidog unterstützt das Testen von Webhooks.
Webhook-Zustellung testen
- Mock-Webhook-Endpunkt in Apidog erstellen
- Endpunkt bei der PetstoreAPI registrieren
- Ereignis auslösen (Haustier adoptieren)
- Verifizieren, ob Webhook empfangen wurde
- Payload-Format überprüfen
Signaturprüfung testen
// Apidog test script
const signature = pm.request.headers.get('X-Webhook-Signature');
const payload = pm.request.body.raw;
const secret = pm.environment.get('WEBHOOK_SECRET');
const expected = generateSignature(payload, secret);
pm.test('Signature valid', () => {
pm.expect(signature).to.equal(`sha256=${expected}`);
});
Wiederholungslogik testen
- 500er-Fehler vom Mock-Endpunkt zurückgeben
- Wiederholungsversuche mit exponentiellem Backoff überprüfen
- Dead Letter Queue nach maximalen Wiederholungsversuchen prüfen
Idempotenz testen
- Webhook empfangen
- 200 zurückgeben
- Denselben Webhook erneut empfangen (simulierter Wiederholungsversuch)
- Verifizieren, dass keine doppelte Verarbeitung stattfindet
Fazit
Zuverlässige Webhooks erfordern:
- Exponentiellen Backoff-Retry (5-10 Versuche)
- Idempotenzschlüssel zur Vermeidung von Duplikaten
- HMAC-Signaturprüfung für die Sicherheit
- 5-Sekunden-Timeouts
- Asynchrone Verarbeitung auf Client-Seite
- Dead Letter Queue für fehlgeschlagene Webhooks
Die moderne PetstoreAPI implementiert all diese Muster. Sehen Sie in der Webhook-Dokumentation nach vollständigen Beispielen.
Testen Sie Ihre Webhooks mit Apidog, um die Wiederholungslogik, Signaturen und Idempotenz vor der Produktivsetzung zu überprüfen.
FAQ
Wie viele Wiederholungsversuche sollten Webhooks haben?
5-10 Versuche mit exponentiellem Backoff. Dies deckt vorübergehende Ausfälle (5-17 Minuten) ab, ohne den Client zu überlasten.
Sollten Webhooks bei 4xx-Fehlern erneut versuchen?
Nein. 4xx-Fehler weisen auf Client-Probleme hin (falsche URL, Authentifizierungsfehler). Ein erneuter Versuch wird diese nicht beheben. Wiederholen Sie nur bei 5xx-Fehlern und Netzwerkfehlern.
Wie lang sollten Webhook-Timeouts sein?
Maximal 5 Sekunden. Clients sollten sofort 200 zurückgeben und asynchron verarbeiten. Längere Timeouts deuten darauf hin, dass der Client eine synchrone Verarbeitung durchführt.
Was, wenn ein Client nie auf Webhooks antwortet?
Nach maximalen Wiederholungsversuchen in die Dead Letter Queue verschieben. Den Client per E-Mail benachrichtigen. Erwägen Sie, Webhooks für diesen Client nach wiederholten Fehlern zu deaktivieren.
Sollten Webhook-URLs HTTPS sein?
Ja, fordern Sie immer HTTPS. HTTP-Webhooks können abgefangen und verändert werden. Die moderne PetstoreAPI lehnt HTTP-Webhook-URLs ab.
Wie verhindern Sie Replay-Angriffe?
Fügen Sie einen Zeitstempel in die Payload ein und lehnen Sie Webhooks ab, die älter als 5 Minuten sind. Kombinieren Sie dies mit der Signaturprüfung.
Können Clients eine erneute Zustellung von Webhooks anfordern?
Ja. Die moderne PetstoreAPI bietet einen Endpunkt zur erneuten Zustellung spezifischer Webhooks: POST /webhooks/{id}/redeliver
Wie testen Sie Webhooks lokal?
Verwenden Sie Tools wie ngrok, um localhost dem Internet zugänglich zu machen, oder nutzen Sie den Mock-Server von Apidog, um Webhook-Endpunkte während der Entwicklung zu simulieren.
