Wywołania zwrotne
Bezpiecznie odbieraj i weryfikuj dostarczenia wywołań zwrotnych zadania.
Używaj wywołań zwrotnych, aby odbierać zdarzenia cyklu życia Zadania (Task) pod publicznym punktem końcowym HTTPS. Weryfikuj każde wywołanie zwrotne przed przetworzeniem jego treści JSON, aby tylko dostarczenia podpisane dla Twojego konta mogły zmieniać stan aplikacji.
Konfiguracja adresu URL wywołania zwrotnego
Dodaj publiczny adres HTTPS callback_url podczas tworzenia zadania (Task).
Treść zdarzenia i stany cyklu życia zależą od punktu końcowego; zapoznaj się
z dokumentacją interfejsu API danego punktu końcowego, aby poznać ładunki
wywołań zwrotnych.
{
"model": "flux-2-pro-text-to-image",
"prompt": "A product photograph on a clean studio background",
"callback_url": "https://your-domain.com/webhooks/runapi"
}
Tworzenie tajnego klucza wywołania zwrotnego
Postępuj zgodnie z Przewodnikiem po uwierzytelnianiu, aby się zalogować, a następnie otwórz sekcję Klucze API i utwórz Callback Secret dla konta, które tworzy zadanie (Task). Przechowuj wartość w menedżerze sekretów i udostępniaj ją wyłącznie odbiorcy wywołań zwrotnych. Nie jest to klucz API i nigdy nie wolno go wysyłać w żądaniu Task.
Sekret podpisuje wywołania zwrotne dla danego konta. Jego rotacja zmienia sygnaturę dla późniejszych dostaw, dlatego natychmiast zaktualizuj każdy odbiornik wywołań zwrotnych i przechowuj obie wartości tylko przez czas niezbędny do obsługi dostarczeń w toku.
Weryfikuj podpis wywołania zwrotnego
Każde wywołanie zwrotne to HTTP POST z nagłówkiem Content-Type: application/json.
RunAPI nie dodaje nagłówka Authorization do tego żądania. Zweryfikuj
następujące nagłówki przed deserializacją treści:
X-Callback-Id
Unikalny identyfikator tej próby dostarczenia.
X-Callback-Timestamp
Znacznik czasu Unix w sekundach określający moment podpisania dostarczenia.
X-Callback-Signature
Podpis HMAC-SHA-256 zakodowany w Base64.
Zbuduj podpisaną wartość dokładnie w następujący sposób, używając niezmodyfikowanych bajtów treści żądania:
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body
Zdekoduj Callback Secret z Base64, oblicz HMAC-SHA-256 na tej
wartości, zakoduj wynik w Base64 i porównaj go z
X-Callback-Signature przy użyciu porównania odpornego na ataki czasowe. Nie parsuj i
nie serializuj ponownie JSON przed weryfikacją.
JavaScript
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyCallback({headers, rawBody, callbackSecret}) {
const callbackId = headers["x-callback-id"];
const timestamp = Number(headers["x-callback-timestamp"]);
const signature = headers["x-callback-signature"];
if (!callbackId || !signature || !Number.isSafeInteger(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const signedContent = `${callbackId}.${timestamp}.${rawBody}`;
const expected = createHmac("sha256", Buffer.from(callbackSecret, "base64"))
.update(signedContent, "utf8")
.digest();
const received = Buffer.from(signature, "base64");
return expected.length === received.length && timingSafeEqual(expected, received);
}
Przekaż surowy ciąg treści żądania ze środowiska do rawBody; nie wywołuj
JSON.stringify na przetworzonych danych.
Python
import base64
import hashlib
import hmac
import time
def verify_callback(headers, raw_body, callback_secret):
callback_id = headers.get("X-Callback-Id")
timestamp = headers.get("X-Callback-Timestamp")
signature = headers.get("X-Callback-Signature")
if not callback_id or not timestamp or not signature:
return False
try:
timestamp = int(timestamp)
secret = base64.b64decode(callback_secret, validate=True)
received = base64.b64decode(signature, validate=True)
except (ValueError, TypeError):
return False
if abs(time.time() - timestamp) > 300:
return False
signed_content = f"{callback_id}.{timestamp}.{raw_body}".encode("utf-8")
expected = hmac.new(secret, signed_content, hashlib.sha256).digest()
return hmac.compare_digest(expected, received)
Przekaż dokładny surowy ciąg treści żądania odebrany przez Twoje środowisko HTTP
jako raw_body.
Bezpieczne przetwarzanie dostaw
- Zwróć odpowiedź
2xxdopiero po zaakceptowaniu wywołania zwrotnego do przetworzenia. Po odpowiedzi innej niż2xxlub awarii transportu dostarczenie jest ponawiane do 10 razy. - Odpowiedz w ciągu 15 sekund. Wolniejsze zadania umieszczaj w kolejce po weryfikacji, zamiast blokować odpowiedź HTTP.
- Odrzucaj wywołania zwrotne z brakującymi nagłówkami podpisu, nieprawidłowym podpisem lub znacznikiem czasu poza oknem tolerancji zdefiniowanym przez odbiornik.
Rozwiązywanie problemów z weryfikacją
- Niezgodność sygnatury: upewnij się, że Callback Secret należy do tego samego konta co Zadanie, zdekoduj go za pomocą Base64 i podpisz oryginalną treść, a nie przeanalizowany JSON.
- Brakujące nagłówki sygnatury: utwórz Callback Secret przed poleganiem na wywołaniach zwrotnych w przypadku zmian stanu.
- Znacznik czasu odrzucony: zsynchronizuj zegar odbiornika i użyj tolerancji odpowiedniej dla swojego wdrożenia.
W celu uzyskania wskazówek dotyczących konfiguracji i cyklu życia wróć do Szybkiego startu Task API.