Przejdź do treści głównej

Przewodnik wdrożeniowy

Dokończ pracę, gdy żądania już nie ma.

Zadanie multimedialne przeżywa wywołanie HTTP, które je utworzyło, stronę, która je uruchomiła, a często i wdrożenie działające w tamtej chwili. Wszystko tutaj służy temu, żeby dało się to przeżyć.

Wyzwanie

Połączenie to nie jest transakcja

Między naciśnięciem „wyślij” a plikiem w ręku są cztery miejsca, w których gubi się pracę: utworzenie zakończone timeoutem, ponawiane na ślepo, wywołanie zwrotne, którego nie da się uwierzytelnić, pętla odpytywania, która albo młóci, albo się poddaje, i adres wyniku, który wygasł w trakcie namysłu, co z nim zrobić.

01

Ponowione utworzenie bez klucza to drugi rachunek

Idempotency-Key sprawia, że powtórzenie tego samego modelu, wejścia i wywołania zwrotnego w ciągu 24 godzin zwraca pierwotne zadanie, zamiast blokować środki po raz drugi. Działa w zakresie jednego klucza API – bliźniaczy klucz powtarzający tę samą wartość dostaje 409 i żadnego identyfikatora zadania.

02

Niezweryfikowane wywołanie zwrotne to otwarty endpoint

Dostarczenia niosą X-Webhook-Timestamp i zakodowany w Base64 HMAC-SHA256 w X-Webhook-Signature, liczony z taskId.timestamp.sha256(raw_body). Weryfikuj na surowych bajtach w stałym czasie i odrzucaj przeterminowane znaczniki czasu, zanim ruszysz stan zadania albo rozliczeń.

03

Odpytywanie bez sufitu to limit żądań czekający, aż się wydarzy

recordInfo to zabezpieczenie, a nie transport. Zacznij od mniej więcej dwóch sekund, wydłużaj odstęp o połowę, zatrzymaj się na piętnastu i przerwij w terminie wybranym przez siebie, a nie przez sieć.

Podejście

Jeden trwały rekord na zadanie, zapisany przed odpowiedzią

Zapisz klucz idempotentności, taskId i własny identyfikator korelacji w tej samej transakcji, która odpowiada wołającemu. Każde późniejsze zdarzenie – wywołanie zwrotne, odpytanie, ponowienie, pytanie od wsparcia – rozstrzyga się na tym wierszu, a zdublowane dostarczenie staje się aktualizacją zamiast drugim zamówieniem.

Najpierw weryfikuj, potem czytaj. Podpis obejmuje surowe bajty, więc parsuj dopiero po udanym porównaniu.

Verify the callback before you trust it

import { createHash, createHmac, timingSafeEqual } from "node:crypto";

// rawBody is the exact bytes that arrived. Parse only to read the task ID:
// the digest is always computed over those raw bytes, never over a re-encode.
export function verifyDelivery(rawBody, headers, webhookKey) {
  const timestamp = headers["x-webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const taskId = JSON.parse(rawBody).data.taskId;          // payload version 2
  const digest = createHash("sha256").update(rawBody).digest("hex");
  const expected = createHmac("sha256", webhookKey)
    .update(`${taskId}.${timestamp}.${digest}`)
    .digest("base64");

  const sent = Buffer.from(headers["x-webhook-signature"] ?? "", "utf8");
  const mine = Buffer.from(expected, "utf8");
  return sent.length === mine.length && timingSafeEqual(sent, mine);
}

Delivery headers

X-Webhook-Timestamp: 1788652800
X-Webhook-Signature: <base64>
X-Webhook-Payload-Version: 2

{
  "code": 200,
  "msg": "success",
  "request_id": "whd_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "data": { "taskId": "job_01k3…", "state": "succeeded", "settled": true, … }
}

Kontrakt

Co warto ustalić na starcie

Asynchroniczne API mediów: zadania i webhooki — Co warto ustalić na starcie
Pole lub nagłówekWartość lub limit
Idempotency-Key24 h · scoped to one API key
X-Webhook-Signaturebase64(HMAC-SHA256)
signed stringtaskId.timestamp.sha256(raw_body)
X-Webhook-Payload-Version2 for new integrations

Przesuń w poziomie, żeby zobaczyć wszystkie kolumny.

Integracja

Od pierwszego wywołania do produkcji

  1. 01Wygeneruj i zapisz klucz idempotentności, a potem wyślij POST createTask z nim oraz z callBackUrl wskazującym endpoint HTTPS na porcie 80 albo 443.
  2. 02Zapisz data.taskId w swojej bazie, zanim odpowiesz wołającemu – w odpowiedzi 202 pojawia się on po raz pierwszy.
  3. 03Przyjmij wywołanie zwrotne, zweryfikuj podpis na surowej treści, odfiltruj duplikaty po request_id i zaktualizuj swój rekord.
  4. 04W razie potrzeby sięgnij po recordInfo z wykładniczym odstępem i skopiuj output.assets do własnego magazynu, zanim podpisany adres wygaśnie.

Dopasowanie

Kiedy ta droga jest właściwa

Wybierz to, gdy

  • Wszystko, co tworzy media. Endpointy obrazu, wideo i dźwięku są asynchroniczne z założenia.
  • Potrzebujesz trwałego zapisu tego, co wysłano, ile to miało kosztować i jak się skończyło.

Poszukaj gdzie indziej, gdy

  • Wołasz model tekstowy. Te strumieniują w obrębie żądania i rozliczają się na zmierzonym zużyciu.
  • Chcesz, żeby zadanie należało do przeglądarki. Klucze mają być po stronie twojego serwera, podobnie jak rekord zadania.

Dowody

Co możesz sprawdzić samodzielnie

Każda odpowiedź niesie request_id

Struktura odpowiedzi to {code, msg, data, request_id} przy każdej operacji /api/v1. W wersji 2 ładunku request_id dostarczenia pozostaje stabilny między ponowieniami, co czyni go naturalnym kluczem deduplikacji.

Blokady widać w rekordzie

cost z settled: false to zarezerwowana wycena, a settled: true to końcowa opłata. Powodzenie nigdy nie przekracza blokady, a niepowodzenie albo wygaśnięcie zwalnia ją w całości.

Błędy mają zamknięty słownik

errorCode to jedna z dziewięciu stabilnych wartości: invalid_request, unsupported_combination, content_rejected, rate_limited, upstream_unavailable, generation_failed, timeout, invalid_asset, upstream_failed. Wszystko inne traktuj jak upstream_failed.

Przed startem

Zachowania platformy do potwierdzenia

  • Trzymaj klucz idempotentności razem z zadaniem, a nie w pamięci procesu.
  • Zrób obsługę wywołania zwrotnego idempotentną – dostarczenia są ponawiane z założenia.
  • Ustaw termin dla odpytywania i alarmuj o zadaniach, które go przekroczą.
  • Kopiuj pliki przed expiresAt i proś o nowy adres, zamiast buforować podpisany.

FAQ

O co pytają na tej stronie

Ponów to samo żądanie z tym samym nagłówkiem Idempotency-Key. W ciągu 24 godzin i na tym samym kluczu API wróci pierwotne zadanie bez drugiej blokady. Nigdy nie wysyłaj po timeoucie nowej treści – to już osobne, osobno płatne zadanie.

Co dalej

Zbuduj przepływ zadań, który przetrwa wdrożenie

Wysyłaj długie zadania multimedialne z serwera i kończ je pewnie: klucze idempotentności, podpisane wywołania zwrotne, ograniczone odpytywanie.

Powiązane przewodniki