Obsługa błędów i kody stanu
1) Dlaczego ujednolicić błędy
Pojedyncza umowa o błąd przyspiesza debugowanie klienta, zmniejsza fałszywe przekłady i sprawia, że RCA jest odtwarzalne. Dobry system:- przewidywalnie koduje typ problemu,
- daje klientowi ważne wiersze (co zrobić dalej),
- chroni przed wyciekiem części wewnętrznych,
- kompatybilny z retrasami i idempotencją.
2) Zasady projektowania
1. Jeden system błędów dla wszystkich usług (REST/GraphQL/gRPC/webhooks).
2. Jasne semantyki retras: które kody do wycofania, które nie.
3. Nieudane operacje pisania: lepsze 4xx/5xx niż cicha niespójność.
4. Brak przecieków: nie ujawniać SQL, stosy, konfiguracje, wewnętrzne identyfikatory.
5. Trace - Zawsze zwracaj 'trace _ id'/' correlation _ id'.
6. Lokalizacja wiadomości jest opcjonalna, ale kody i 'resason' pozostają stabilne.
3) Jednolity format (Szczegóły problemu/JSON)
Zalecany format podstawowy (zgodny z RFC 7807):json
{
"type": "https://errors.example.com/auth/invalid-token",
"title": "Invalid access token",
"status": 401,
"code": "AUTH_INVALID_TOKEN",
"detail": "Token expired or signature invalid.",
"instance": "/api/v1/payments/12345",
"trace_id": "01HX3...ABC",
"hint": "Obtain a new token via OAuth2 refresh.",
"meta": {
"scope": "payments:write",
"policy": "deny-by-default"
}
}
Wyjaśnienia:
- 'type' to stabilny adres URL klasy błędów.
- „kod” - krótki kod maszyny domeny (stabilny między wydaniami).
- „wskazówka” - co zrobić dla klienta (powtórzyć, zaktualizować token, zmienić parametry).
- „meta” - części zabezpieczone (bez tajemnic i PII).
4) Mapa kodu statusu (minimalny zestaw)
Uwierzytelnianie/autoryzacja
400 Bad Request - zatwierdzenie strukturalne/program.
401 Nieautoryzowany - nie/nieprawidłowy token. Dodaj 'WWW-Authenticate'.
403 Zakazane - uwierzytelnione, ale pozbawione praw/polityk.
404 Nie znaleziono - maska istnienie zasobu bez praw.
409 Konflikt - wersja/konflikt państwa (optymistyczny zamek, idempotencja).
451 Niedostępne ze względów prawnych - zgodność/blok jurysdykcyjny.
Granice i ochrona
408 Żądanie Timeout - Klient przesyła ciało zbyt powoli.
409/425 Zbyt wcześnie - zakaz wczesnego powtarzania w 0-RTT/TLS 1. 3.
429 Zbyt wiele żądań - z „Retry-After” i ograniczyć politykę.
499 Klient zamknięte żądanie - (na obwodzie/NGINX) klient odłączył połączenie.
Zasady dotyczące danych i działalności gospodarczej
422 Nieprzetworzona treść - walidacja firmy przeszła program, ale znaczenie jest nieprawidłowe.
423 Zablokowany - zablokowany zasób (przegląd KYC, zamrożenie AML).
409 Konflikt - podwójne zgłoszenie, wyścig, limit statusu (na przykład „już w toku”).
410 Zniknął - usunięty punkt końcowy/zasób (zakończony).
Serwer
Błąd serwera wewnętrznego 500 - nieznany błąd; nie ujawniają szczegółów.
502 Bad Gateway - zwracany błąd/serwer proxy.
503 Serwis niedostępny - degradacja/planowane prace; Dodaj 'Retry-After'.
504 Brama Timeout.
5) Przekaźnik i semantyka idempotencji
Nie można wycofać 400/ 401/403/404/422 (chyba że klient zmienił żądanie).
Można wycofać: 408/429/5xx/ 425/499/504 (z backoff + jitter).
Idempotencja: Dla 'POST', włącz 'Idempotence-Key' (UUIDv4).
W przypadku powtórnego konfliktu należy zwrócić 409 z napisem: "Użyj tego samego Idempotence-Key lub GET status" ".
Dodaj 'Idempotence-Replay: true' when zwracając zapisany wynik.
HTTP/1.1 429 Too Many Requests
Retry-After: 3
RateLimit-Limit: 50
RateLimit-Remaining: 0
RateLimit-Reset: 1730641030
6) Walidacja wejściowa: struktura błędu pola
W przypadku 400/422 należy użyć tablicy błędów w polu:json
{
"type": "https://errors.example.com/validation",
"title": "Validation failed",
"status": 422,
"code": "VALIDATION_ERROR",
"trace_id": "01HX4...XYZ",
"errors": [
{"field": "amount", "rule": "min", "message": "Must be >= 10"},
{"field": "currency", "rule": "enum", "message": "Unsupported currency"}
]
}
7) Częściowe awarie (partia/częściowa awaria)
W punktach końcowych partii nie ukrywać błędów wewnątrz 200 bez struktury. Powrót 207 Multi-Status lub 200 z tablicą wyników, gdzie każde zadanie ma swój własny status:json
{
"status": "partial",
"succeeded": 8,
"failed": 2,
"results": [
{"id": "op1", "status": 201},
{"id": "op2", "status": 422, "error": {"code":"VALIDATION_ERROR","detail":"..."}}
]
}
8) Paginacja i „puste” odpowiedzi
Pusta kolekcja - 200 s „pozycji: []”, nie 404.
Koniec strony - brakuje 'next _ page _ token'.
Nieprawidłowy token - kod 400 s: PAGINATION_CURSOR_INVALID'.
9) Haki internetowe: niezawodna dostawa
Podpisz zdarzenia (HMAC) i sprawdź przed przetworzeniem.
Odpowiedź na udane przetwarzanie wynosi 2xx (najlepiej 204).
Tymczasowe awarie odbiornika - 5xx; nadawca powtarza (wykładnicze backoff, jitter).
Deduplikowanie przez 'event _ id' i zapisywanie wyniku (konsument idempotent).
Nieprawidłowy ładunek - 400/422 nie próbuje ponownie.
10) Zgodność protokołu (gRPC/GraphQL)
gRPC → HTTP:- „NIEPRAWIDŁOWY ARGUMENT” → 400
- „NIEAUTORYZOWANE” → 401
- „POZWOLENIE _ ODMÓWIONE” → 403
- „NIE ZNALEZIONO” → 404
- „JUŻ _ ISTNIEJE” → 409
- „NIEUDANY _ WARUNEK WSTĘPNY” → 412/422
- „ZASOBY _ WYCZERPANE” → 429
- „ABORTED” → 409
- „NIEDOSTĘPNY” → 503
- „TERMIN _ PRZEKROCZONY” → 504
json
{
"data": { "createPayment": null },
"errors": [{
"message": "Forbidden",
"extensions": { "code": "FORBIDDEN", "status": 403, "trace_id": "..." },
"path": ["createPayment"]
}]
}
Zaleca się użycie odpowiedniego kodu HTTP zamiast 200 dla błędów krytycznych.
11) Tytuły i wskazówki dla klientów
„Retry-After” - sekundy/data HTTP (429/503/425/408).
„Ostrzeżenie” - miękka degradacja lub deprekacja („199 - cecha X jest przygnębiona”).
"Deprecacja", "Zachód słońca", "Link: <...>; rel = „deprecation” - dla kontrolowanego wyłączenia.
'Problem-Type' (custom) - szybki błąd routingu na kliencie.
'X-Trace-Id'/' Correlation-Id' - łączy kłody/ślady.
12) Bezpieczeństwo wiadomości
Nie należy powtarzać tajemnic wejściowych (żetonów/podpisów) w organizmie odpowiedzi.
Maska PAN/PII („1234”).
Dla 401/403 - nie ujawniaj, który atrybut nie powiódł się.
Dla 404, zamiast „zasoby istnieją, ale nie twoje” - tylko 404.
13) Obserwowalność błędów
Metryka:- „http _ errors _ total {status, route, najemca}”
- 'error _ classes _ total {code}' (przez 'code' z ciała)
- udział 429, 5xx; „p95 ”/„ p99” opóźnienie dla błędnych odpowiedzi oddzielnie
- „retry _ after _ seconds _ bucket” - histogram końcówek powtarzalności
- skojarzyć odpowiedź z 'trace _ id',' store code ',' type ',' status ',' trasa ',' lokator ', no PII.
- spike '5xx _ rate> X%' przy RPS> N;
- wzrost o 429 na trasach krytycznych;
- „timeout/504” zależności;
- częste 409/idempotencja → znak wyścigów.
14) Przykłady
14. 1422 (walidacja działalności gospodarczej)
json
{
"type": "https://errors.example.com/payments/limit-exceeded",
"title": "Limit exceeded",
"status": 422,
"code": "PAYMENT_LIMIT_EXCEEDED",
"detail": "Daily withdrawal limit reached for KYC1.",
"hint": "Increase limits after KYC2 or try tomorrow.",
"trace_id": "01J5...XYZ"
}
14. 2409 (idempotencja)
HTTP/1.1 409 Conflict
Idempotency-Replay: true
json
{
"type": "https://errors.example.com/idempotency/replay",
"title": "Duplicate request",
"status": 409,
"code": "IDEMPOTENT_REPLAY",
"detail": "A request with the same Idempotency-Key was already processed.",
"hint": "Reuse the same Idempotency-Key and GET the operation status."
}
14. 3,429 (limity)
json
{
"type":"https://errors.example.com/rate/too-many-requests",
"title":"Too many requests",
"status":429,
"code":"RATE_LIMITED",
"detail":"Per-key rate limit exceeded.",
"hint":"Retry after the time specified in Retry-After header."
}
15) Antypattery
Zwróć 200 z tekstem błędu ciała.
Wymieszaj różne formaty błędów między usługami.
Rozwiń stos/SQL/nazwy tabeli/wewnętrzne adresy URL w 'detail'.
Użyj „wiadomości” zamiast stabilnego „kodu ”/„ typu”.
Zwrot 500 w przypadku wystąpienia oczekiwanego błędu biznesowego (na przykład „saldo jest niewystarczające”).
Niespójna semantyka pomiędzy REST/GraphQL/gRPC.
16) Szczegóły dotyczące iGaming/Finance
Jasne kody KYC/AML/sankcji: „KYC _ REQUIRED”, „KYC _ REVIEW”, „AML _ LOCK”, „SANKCJA _ BLOKOWANA”.
Ograniczenia jurysdykcyjne: 451 z bezpiecznym brzmieniem bez notowania.
Operacje monetarne: 409/423 dla konkurencji i zamków, „wskazówka” z oknem redo.
Limit gracza niezmiennie: Użyj 422 do odpowiedzialnych naruszeń płatności.
Audyt: niezmienne dzienniki rozwiązań (kod, czas, aktor, trace_id).
17) Lista kontrolna gotowości Prod
- Jednolity system błędów JSON, stabilny „typ ”/„ kod”.
- Odwzorowanie HTTP i GRPC/GraphQL jest spójne i udokumentowane.
- Semantyka retrasy + „Retry-After”; idempotencja do pisania.
- PII/tajne maskowanie; 404 ukryć zasoby.
- Wskaźniki błędów i alarmów; korelacja z 'trace _ id'.
- Polityka deprecjacji: „Deprecacja”, „Zachód słońca”, „Link”.
- Testy: negatywne/fuzz, konflikt wersji, spadek zależności, podwójne zgłoszenie.
- Przewodnik po kliencie: Przykłady cofania i przetwarzanie 409/422/429/5xx.
18) TL; DR
Ujednolicenie pojedynczego formatu błędu JSON z 'type '/' code '/' trace _ id', użycie prawidłowych kodów HTTP, rozróżnienie między walidacją (400/422), prawami (401/403/404), konfliktami/idempotencją (409) i limitami (429). Należy podać wyraźne 'Retry-After' i 'hint', dane wrażliwe na maskę, błędy dziennika z 'trace _ id' i skonstruować wpisy o 5xx/429/p99.