Eroare de manipulare și coduri de stare
1) De ce să standardizați erorile
Un singur contract de eroare accelerează depanarea clienților, reduce retraiele false și face ca RCA să poată fi redat. Sistem bun:- codifică în mod previzibil tipul de problemă,
- oferă clientului solicitări valide (ce trebuie făcut în continuare),
- protejează împotriva scurgerilor de părți interne,
- compatibil cu retras și idempotență.
2) Principii de proiectare
1. O schemă de eroare pentru toate serviciile (REST/GraphQL/gRPC/webhooks).
2. Semantica clară a retroaielor: care coduri pentru a retrage, care nu.
3. Eșec-închis pe operațiunile de scriere: mai bine 4xx/5xx decât inconsecvență liniștită.
4. Nu există scurgeri: nu divulgați SQL, stive, configurații, ID-uri interne.
5. Trace - Intotdeauna returnati 'trace _ id'/' corelation _ id'.
6. Localizarea mesajelor este opțională, dar codurile și 'reason' rămân stabile.
3) Format unic (Detalii problemă/JSON)
Formatul de bază recomandat (conform 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"
}
}
Explicaţii:
- 'type' este un URL stabil de clasă de eroare.
- 'code' - cod scurt al mașinii de domeniu (stabil între versiuni).
- „indiciu” - ce trebuie să faceți pentru client (repetați, actualizați jetonul, schimbați parametrii).
- „meta” - piese securizate (fără secrete și PII).
4) Harta codului de stare (set minim)
Autentificare/Autorizare
400 Cerere proastă - validare structurală/schemă.
401 Neautorizat - nu/token nevalid. Adaugă „WWW-Authenticate”.
403 Interzis - autentificat, dar fără drepturi/politici refuzate.
404 Not Found - maschează existența unei resurse fără drepturi.
409 Conflict - conflict versiune/stat (blocare optimistă, idempotență).
451 Indisponibil din motive juridice - bloc de conformitate/jurisdicție.
Limite și protecție
408 Cerere Timeout - Clientul trimite corpul prea încet.
409/425 Prea devreme - interzicerea repetării timpurii în 0-RTT/TLS 1. 3.
429 Prea multe cereri - cu „Retry-After” și politica de limită.
499 Client Closed Request - (la perimetrul/NGINX) clientul a deconectat conexiunea.
Date și reguli de afaceri
422 Conținut neprelucrabil - validarea afacerii a trecut schema, dar sensul este incorect.
423 Blocat - resursă blocată (recenzie KYC, îngheț AML).
409 Conflict - dublă depunere, rasă, limită de stare (de exemplu, „deja în proces”).
410 Gone - punct final/resursă ștearsă (depreciați complet).
Server
500 Eroare server intern - eroare necunoscută; nu dezvăluie detalii.
502 Bad Gateway - dependență a revenit eroare/proxying.
503 Service Indisponibil - degradare/planificare lucrari; adăugați „Retry-After”.
504 Gateway Timeout.
5) Semantica de retransmisie și idempotență
Nu puteți retrage 400/ 401/403/404/422 (cu excepția cazului în care clientul a schimbat cererea).
Puteți retrage: 408/429/5xx/ 425/499/504 (cu backoff + jitter).
Idempotency: Pentru 'POST', activați 'Idempotency-Key' (UUIDv4).
Pentru un conflict din nou, returnați 409 cu 'indiciu: "Utilizați aceeași Idempotency-Key sau statutul GET" ".
Adăugați 'Idempotency-Replay: true' when returnarea unui rezultat salvat.
HTTP/1.1 429 Too Many Requests
Retry-After: 3
RateLimit-Limit: 50
RateLimit-Remaining: 0
RateLimit-Reset: 1730641030
6) Validarea intrărilor: structura erorii câmpului
Pentru 400/422, utilizaţi o serie de erori de câmp: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) Defecțiuni parțiale (lot/eșec parțial)
În punctele finale ale lotului, nu ascundeți erorile în interiorul 200 fără structură. Return 207 Multi-Status sau 200 cu o serie de rezultate, în cazul în care fiecare sarcină are propriul statut:json
{
"status": "partial",
"succeeded": 8,
"failed": 2,
"results": [
{"id": "op1", "status": 201},
{"id": "op2", "status": 422, "error": {"code":"VALIDATION_ERROR","detail":"..."}}
]
}
8) Paginare și răspunsuri „goale”
Colecție goală - 200's items: [] ', nu 404.
Sfârșitul paginii - „next _ page _ token” lipsește.
Token incorect - codul 400: PAGINATION_CURSOR_INVALID'.
9) Webhooks: Livrare de încredere
Semnați evenimente (HMAC) și verificați înainte de procesare.
Răspunsul la procesarea cu succes este 2xx (cel mai bun 204).
Receptor eșecuri temporare - 5xx; expeditorul repetă (backoff exponențial, jitter).
Deduplicarea prin 'event _ id' și salvarea rezultatului (consumator idempotent).
Sarcină utilă nevalidă - 400/422 fără reîncărcări.
10) Conformitatea protocolului (gRPC/GraphQL)
gRPC → HTTP:- 'INVALID _ ARGUMENT' → 400
- „NEAUTENTICAT” → 401
- 'PERMISIUNE _ REFUZAT' → 403
- 'NOT _ FOUND' → 404
- 'DEJA _ EXISTĂ' → 409
- „EŞEC _ CONDIŢIE PREALABILĂ” → 412/422
- „RESURSE _ EPUIZAT” → 429
- „AVORTAT” → 409
- „INDISPONIBIL” → 503
- „Termen limită _ DEPĂȘIT” → 504
json
{
"data": { "createPayment": null },
"errors": [{
"message": "Forbidden",
"extensions": { "code": "FORBIDDEN", "status": 403, "trace_id": "..." },
"path": ["createPayment"]
}]
}
Se recomandă utilizarea codului HTTP corespunzător în loc de 200 pentru erori critice.
11) Titluri și sfaturi pentru clienți
„Retry-After” - secunde/HTTP data (429/503/425/408).
„Avertizare” - degradare moale sau depreciere („199 - Caracteristica X este deprimată”).
'Depreciere', 'Apus de soare', 'Legătură: <...>; rel = „depreciere” - pentru oprire controlată.
'Problem-Type' (personalizat) - rutare rapidă a erorilor pe client.
„X-Trace-Id'/” Corelation-Id' - legături jurnale/urme.
12) Securitatea mesajului
Nu repetați secretele de intrare (jetoane/semnături) în corpul de răspuns.
Mască PAN/PII ('1234').
Pentru 401/403 - nu dezvăluiți ce atribut a eșuat.
Pentru 404, în loc de „resursă există, dar nu a ta” - doar 404.
13) Observabilitatea erorilor
Măsurători:- 'http _ errors _ total {status, route, chiriaș}'
- 'error _ classes _ total {code}' (prin 'code' din corp)
- cota 429, 5xx; „p95 ”/„ p99” latență pentru răspunsuri eronate separat
- 'retry _ after _ seconds _ bucket' - histograma tipurilor de repetiție
- asociază răspunsul cu 'trace _ id',' code ',' type ',' status ',' route ',' renant ', no PII.
- spike '5xx _ rate> X%' la RPS> N;
- creșterea cu 429 pe rute critice;
- 'timeout/504' de dependenţe;
- frecvente 409/idempotenta → un semn de curse.
14) Exemple
14. 1,422 (validarea afacerilor)
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. 2,409 (idempotență)
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 (limite)
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) Antipattern
Returnați 200 cu textul de eroare al corpului.
Se amestecă diferite formate de eroare între servicii.
Extindeți numele stivei/SQL/tabelului/adresele URL interne în 'deletail'.
Utilizați „mesaj” în loc de stabil „cod ”/„ tip”.
Return 500 atunci când apare o eroare de afaceri așteptată (de exemplu, „soldul este insuficient”).
Semantică inconsecventă între REST/GraphQL/gRPC.
16) Specificul iGaming/Finanțe
Coduri clare pentru KYC/AML/sancțiuni: 'KYC _ REQUIRED',' KYC _ REVIEW ',' AML _ LOCK ',' SANCȚIUNE _ BLOCAT '.
Restricții jurisdicționale: 451 cu formulare securizată fără listare.
Operațiuni de scriere monetară: 409/423 pentru concurență și încuietori, „indiciu” cu o fereastră refăcută.
Player limit invariants: Utilizați 422 pentru încălcări responsabile de plată.
Audit: jurnale de soluții neschimbabile (cod, timp, actor, trace_id).
17) Lista de verificare Prod Readiness
- O singură schemă de eroare JSON, stabilă „tip ”/„ cod”.
- Cartografierea HTTP ↔ gRPC/GraphQL este consecventă și documentată.
- Retray semantica + 'Retry-After'; idempotență pentru a scrie.
- PII/mascare secretă; 404 pentru a ascunde resursele.
- Eroare și indicatori de alertă; corelația cu "trace _ id'.
- Depreciază politicile: 'Depreciere', 'Apus de soare', 'Legătură'.
- Teste: negativ/fuzz, conflict versiune, dependență picătură, dublu-supune.
- Ghidul clientului: Exemple de rezervă și procesare 409/422/429/5xx.
18) TL; DR
Standardizați un singur format de eroare JSON cu 'type '/' code '/' trace _ id', utilizați codurile HTTP corecte, distingeți între validare (400/422), drepturi (401/403/404), conflicte/idempotență (409) și limite (429). Dați clar 'Retry-After' și 'indiciu', mascați date sensibile, erori de jurnal cu 'trace _ id' și construiți alerte cu 5xx/429/p99.