Błędy API
Jak obsługiwać błędy z API FourA.
Format odpowiedzi o błędzie
Dla wszystkich błędów API zwraca płaskie obiekty JSON. Nie ma tu zagnieżdżonego obiektu error ani kodów błędów.
{
"error": "Invalid API key"
}
Niektóre błędy zawierają dodatkowe pola na najwyższym poziomie, takie jak status, service, retryAfter, current lub limits:
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": { "concurrency": 12, "rpm": 3000 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
Śledzenie requestu
Każda odpowiedź API (sukces lub błąd) zawiera header X-Foura-Request-Id z UUID dla tego wywołania. Loguj go po swojej stronie. Jeśli będziesz musiał zapytać support, co stało się z konkretnym requestem, ten ID pozwoli nam go znaleźć.
curl -i -X POST https://eu.api.foura.ai/api/single/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"method": "GET", "url": "https://example.com"}'
# HTTP/1.1 200 OK
# X-Foura-Request-Id: 9f1c4e6c-7b2a-4d3e-8a1f-2c9d8e4a3b15
# Content-Type: application/json
# ...
Typy błędów
400: Bad Request
W body requestu brakuje wymaganych pól, zawiera ono nieprawidłowe wartości lub wskazuje cel, którego API odmawia pobrania.
{
"error": "Invalid request body format"
}
Ten sam błąd 400 obejmuje również ochronę przed SSRF. Jeśli Twój url wskazuje na prywatny, pętli zwrotnej (loopback) lub w inny sposób zarezerwowany zakres adresów IP (RFC 5735, RFC 6598, zarezerwowane bloki IPv6), request zostanie odrzucony, zanim opuści sieć FourA:
{
"error": "Target <ip> resolves to a private/reserved IP"
}
Rozwiązanie: Upewnij się, że Twój request zawiera wszystkie wymagane pola, adresy URL używają http:// lub https://, a host wskazuje na publiczny adres.
401: Unauthorized
Twój klucz API jest nieprawidłowy lub go brakuje.
Brakujący klucz:
{
"error": "Missing API key. Include X-API-Key header."
}
Nieprawidłowy klucz:
{
"error": "Invalid API key"
}
Rozwiązanie: Sprawdź, czy Twój header X-API-Key zawiera poprawny klucz. W razie potrzeby wygeneruj nowy klucz w Dashboardzie.
429: Rate Limited
Wysłałeś zbyt wiele requestów w krótkim czasie.
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": { "concurrency": 12, "rpm": 3000 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
Rozwiązanie: Odczekaj liczbę sekund podaną w retryAfter przed wysłaniem kolejnych requestów. Szczegóły znajdziesz w sekcji Rate Limits.
500: Server Error
Coś poszło nie tak po naszej stronie.
Rozwiązanie: Ponów request po krótkiej chwili. Jeśli błąd nadal występuje, sprawdź stronę statusu lub skontaktuj się z supportem, podając X-Foura-Request-Id z nieudanej odpowiedzi.
503: Service Disabled or At Capacity
Błąd 503 oznacza, że usługa jest tymczasowo niedostępna z powodu prac konserwacyjnych lub osiągnąłeś limit współbieżności. Obie odpowiedzi zawierają pole retryAfter. Wariant związany z limitami współbieżności zawiera również pola current i limits.
{
"error": "Service disabled",
"status": 503,
"retryAfter": 60
}
Rozwiązanie: Odczekaj tyle sekund, ile podano w retryAfter, a następnie ponów próbę. Aktywne okna serwisowe znajdziesz na stronie statusu.
Błędy po stronie celu wewnątrz 200 OK
Nie każdy błąd objawia się statusem HTTP innym niż 2xx. Gdy strona docelowa zwraca HTTP 200 z informacją o błędzie, FourA nadal przekazuje Ci body, ale klasyfikuje request jako application_error. Gdy cel zwraca status inny niż 2xx, którego nie akceptują Twoje reguły validate, wynikiem jest application_fail, a body przechodzi bez zmian.
Oba przypadki są taryfikowane tak, jakby request zakończył się sukcesem na poziomie sieciowym. Pełną taksonomię znajdziesz w dokumentacji Outcomes.
Kodowanie odpowiedzi
FourA automatycznie dekoduje body odpowiedzi do UTF-8. Jeśli cel serwuje kodowanie windows-1251, gbk, shift_jis, iso-8859-* lub jakikolwiek inny zestaw znaków zadeklarowany w nagłówku Content-Type lub tagu HTML <meta charset>, otrzymasz czysty ciąg znaków UTF-8 w polu data (single, proxy) lub body (browser).
W przypadku danych binarnych (obrazy, protobuf, surowy dźwięk), ustaw returnBuffer: true w requeście. Body zostanie zwrócone jako bufor base64 bez stosowania transkodowania znaków.
Strategia ponawiania prób
Praktyczna polityka ponawiania prób:
import time
import requests
def make_request(url, payload, api_key, max_retries=3):
for attempt in range(max_retries):
resp = requests.post(
url,
headers={"X-API-Key": api_key, "Content-Type": "application/json"},
json=payload,
)
if resp.status_code == 200:
return resp.json()
body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
retry_after = body.get("retryAfter", 2 ** attempt)
request_id = resp.headers.get("X-Foura-Request-Id", "?")
if resp.status_code in (429, 503):
time.sleep(retry_after)
continue
if resp.status_code >= 500:
time.sleep(2 ** attempt)
continue
# 400/401/404 won't fix themselves
raise RuntimeError(f"{resp.status_code} (request {request_id}): {body.get('error')}")
raise RuntimeError(f"Exhausted {max_retries} retries")
Powiązane
- Rate Limits: Szczegóły dotyczące współbieżności i RPM
- Request Outcomes: Wyjaśnienie siedmiu wartości outcome
- Common Issues: Objawy, przyczyny, rozwiązania