Skip to Content
WebhooksPrzykłady

Przykłady webhooków

Ta strona zawiera kompletne, gotowe do produkcji przykłady odbierania i przetwarzania webhooków Ignite w różnych językach programowania.

Pełne przykłady serwera

// pages/api/webhook.ts import { createHmac, timingSafeEqual } from "crypto"; import { NextApiRequest, NextApiResponse } from "next"; // Disable body parser to access raw body for signature verification export const config = { api: { bodyParser: false, }, }; interface ThumbnailFormat { url: string; fileSize: number; } interface ThumbnailVariant { name: string; width: number; height: number; formats: { jpeg: ThumbnailFormat; webp: ThumbnailFormat; }; } interface VideoWebhookData { id: string; status: "COMPLETE" | "PROCESSING" | "NO_FILE" | "FAILED"; title: string; src?: { thumbnails?: ThumbnailVariant[]; thumbnailUrl?: string; // deprecated — use src.thumbnails instead mp4?: Array<{ name: string; url: string; width: number; height: number }>; }; // ... other video properties } async function getRawBody(req: NextApiRequest): Promise<string> { const chunks: Buffer[] = []; for await (const chunk of req) { chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk); } return Buffer.concat(chunks).toString("utf-8"); } function isValidSignature( rawBody: string, signatureHeader: string | string[] | undefined, secret: string ): boolean { try { if (typeof signatureHeader !== "string") { return false; } const time = signatureHeader.match(/t=(\d+)/)?.[1]; const token = signatureHeader.match(/v1=(\w+)/)?.[1]; if (!time || !token) { return false; } const signedPayload = `${time}.${rawBody}`; const hmac = createHmac("sha256", secret); const calculatedSignature = hmac.update(signedPayload).digest("hex"); return timingSafeEqual( Buffer.from(token), Buffer.from(calculatedSignature) ); } catch { return false; } } export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method !== "POST") { return res.status(405).end(); } const rawBody = await getRawBody(req); if ( !isValidSignature( rawBody, req.headers["x-webhook-signature"], process.env.WEBHOOK_SIGNING_SECRET! ) ) { console.error("Invalid webhook signature"); return res.status(403).end(); } const eventType = req.headers["x-webhook-event"]; const deliveryId = req.headers["x-webhook-delivery-id"]; const video = JSON.parse(rawBody) as VideoWebhookData; // Process based on event type switch (eventType) { case "video.created": console.log("New video created:", video.id, video.title); // await handleVideoCreated(video); break; case "video.updated": console.log("Video updated:", video.id, video.title); if (video.status === "COMPLETE") { // Video processing finished - update your database // await db.updateVideo(video.id, { // thumbnails: video.src?.thumbnails, // thumbnail: video.src?.thumbnails?.[0]?.formats.jpeg.url, // sizes: video.src?.mp4, // }); } break; case "video.deleted": console.log("Video deleted:", video.id); // await handleVideoDeleted(video); break; } return res.status(204).end(); }

Dostawy webhooków

Każda próba dostarczenia webhooka jest logowana. Jeśli dostawa się nie powiedzie, system automatycznie ponowi próbę.

Status dostawy

StatusOpis
successZdarzenie zostało dostarczone pomyślnie (odpowiedź HTTP 2xx)
failedDostawa nie powiodła się (timeout, HTTP 4xx/5xx, błąd sieci)

Informacje o dostawie

Każdy wpis o dostawie zawiera:

PoleOpis
responseCodeKod statusu HTTP zwrócony przez Twój endpoint
responseBodyTreść odpowiedzi z Twojego endpointu (obcięta przy dużych odpowiedziach)
errorMessageKomunikat błędu, jeśli dostawa się nie powiodła
deliveredAtZnacznik czasu próby dostawy
attemptNumberKtóra to próba (rosnie przy ponowieniach)
nextRetryAtKiedy zaplanowano następne ponowienie (jeśli dotyczy)

Zachowanie przy ponowieniach

  • Nieudane dostawy są automatycznie ponawiane
  • Jeśli ustawiono nextRetryAt, ponowienie jest zaplanowane
  • Jeśli nextRetryAt nie jest ustawione, kolejnych ponowień nie będzie

Dobre praktyki

Stosowanie tych praktyk zwiększa niezawodność przetwarzania webhooków i ułatwia diagnozowanie problemów.

Czas odpowiedzi

Twój endpoint musi odpowiedzieć w ciągu 30 sekund. Przy długo trwających operacjach od razu potwierdź odbiór webhooka i przetwarzaj asynchronicznie:

app.post('/webhook', async (req, res) => { // Immediately acknowledge receipt res.status(200).json({ received: true }); // Process asynchronously (don't await) processWebhookAsync(req.body).catch(console.error); }); async function processWebhookAsync(video) { // Long-running operations here }

Bezpieczeństwo

  • Chroń sekrety — nigdy nie umieszczaj sekretu podpisywania w kodzie po stronie klienta ani w repozytorium
  • Używaj HTTPS — w produkcji zawsze endpointów HTTPS
  • Weryfikuj wszystko — zawsze sprawdzaj podpisy przed przetwarzaniem
  • Ograniczanie częstotliwości — rozważ limitowanie żądań na swoim endpoincie

Niezawodność

  • Idempotentność — zapisuj i sprawdzaj X-Webhook-Delivery-Id, żeby obsłużyć duplikaty dostaw
  • Logowanie — loguj wszystkie żądania webhooków do debugowania
  • Monitoring — ustaw alerty na nieudane przetwarzanie webhooków
  • Obsługa błędów — zwracaj odpowiednie kody HTTP, żeby ponowienia działały poprawnie

Kody statusu HTTP

KodZnaczenie
200-299Sukces — zdarzenie przetworzone
4xxBłąd po stronie klienta — będzie ponowione
5xxBłąd serwera — będzie ponowione

Rozwiązywanie problemów

Brak zdarzeń

  1. Sprawdź, czy subskrypcja webhooka ma status Active
  2. Zweryfikuj, czy wybrane są właściwe typy zdarzeń
  3. Upewnij się, że zdarzenia występują we właściwej przestrzeni roboczej
  4. Sprawdź logi serwera pod kątem przychodzących żądań

Weryfikacja podpisu się nie udaje

  1. Upewnij się, że używasz właściwego sekretu podpisywania (a nie tokena API)
  2. Sprawdź, czy treść żądania nie jest modyfikowana przed weryfikacją
  3. Sprawdź zgodność serializacji JSON (zwarta, bez zbędnych spacji)
  4. Sprawdź, czy nagłówek podpisu jest parsowany poprawnie: t=timestamp,v1=signature

Błędy timeoutu

  1. Odpowiadaj w ciągu 30 sekund
  2. Przenieś długie operacje do przetwarzania w tle
  3. Zwróć od razu 200, przetwarzaj asynchronicznie

Zduplikowane zdarzenia

  1. Wprowadź idempotentność z użyciem X-Webhook-Delivery-Id
  2. Sprawdzaj attemptNumber przy ponowieniach
  3. Przechowuj przetworzone identyfikatory dostaw w bazie danych