Skip to content
Language:hu Author:Laborci Gergely
reliability

Hibakezelés és felhasználói kommunikáció

Célok

A lecke végére meg tudod különböztetni a hiba gépnek, a fejlesztőnek és a felhasználónak szóló formáját, tudsz jó hibaüzenetet írni, ismered a szabványos hibatörzset (Problem Details), és el tudod dönteni, mikor veszélyes az automatikus újrapróbálkozás.

Miért több nézőpontja van a hibának?

Egy webes rendszerben a „hiba” többféle dolgot jelenthet: a böngésző és a szerver közötti kapcsolat hibáját (4.6), hibás felhasználói bevitelt, szerveroldali kivételt vagy külső szolgáltatás (térkép, fizetés, beléptetés) átmeneti kiesését. Ugyanaz a jelenség másképp látszik a felhasználónak („nem ment át a rendelés”) és másképp a fejlesztőnek (időtúllépés, elutasított fizetés, adatbázishiba, hálózati megszakadás).

A hibakezelés ezért két feladat. Egyrészt a rendszernek észlelnie kell, hogy a normál folyamat megszakadt, és lehetőleg biztonságos állapotba kell kerülnie. Másrészt kommunikálnia kell: a gépekkel (státuszkód, hibatörzs), a fejlesztőkkel (napló) és az emberekkel (üzenet). Az első technikai, a második emberi oldal; egyik sem helyettesíti a másikat: egy részletes naplóbejegyzés nem segít annak, aki nem tudja leadni a jelentkezését, egy kedves üzenet pedig nem pótolja a hiba tényleges kezelését.

flowchart LR
    H[Hiba] --> S[HTTP-válasz: státuszkód és hibatörzs]
    H --> N[Napló és diagnózis]
    H --> F[Felhasználói magyarázat]
    F --> K[Biztonságos következő lépés]

A HTTP-válasz: státuszkód és géppel olvasható hibatörzs

A státuszkódokat a 2.4 lecke részletesen tárgyalta: a 4xx a kérést, az 5xx a szerver vagy a mögötte lévő rendszer hibáját jelzi, a 401/403 a hitelesítés és a jogosultság különbségét, a 429 a sebességkorlátozást, a 502/503/504 az átjáró- és elérhetőségi hibákat. A kód elsősorban a szoftveres szereplőknek szól: ennek alapján dönthet például újrapróbálkozásról vagy bejelentkezés kéréséről a kliens.

A kód kevés ahhoz, hogy a kliens okot is kapjon. Az RFC 9457 ezért szabványos hibaformát ír le, a Problem Details-t: az application/problem+json médiatípusú JSON-törzs ezeket a tagokat tartalmazhatja:

Tag Jelentése
type A hibatípus azonosítója (URI); ha hiányzik, about:blank, vagyis a státuszkódon túl nincs külön jelentése.
title Rövid, emberi összefoglaló a hibatípusról; nem változik előfordulásonként.
status A HTTP-státuszkód ennél az előfordulásnál; azonos a tényleges válaszkóddal.
detail Emberi magyarázat erről az előfordulásról; a kliens nem értelmezheti géppel.
instance Az adott előfordulás azonosítója (URI).

A szabvány szerint saját kiegészítő tagok is megengedettek, amelyeket az ismeretlen klienseknek figyelmen kívül kell hagyniuk; és a hibatörzs nem fedhet fel belső részleteket (például hívási vermet), mert az biztonsági kockázat. Kipróbált példa (a Kurzuspont betelt kurzusa):

$ curl -i localhost:8095/api/jelentkezes-hibas
HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{"type":"https://kurzuspont.example/hibak/betelt",
 "title":"A kurzus betelt",
 "status":409,
 "detail":"A Webprogramozás 1. kurzusra nincs szabad hely.",
 "instance":"/api/jelentkezesek/kerelem/8841"}

A kliens a type alapján dönti el, mit tegyen (például felkínál másik kurzust); a detail emberi olvasóra szól. Ez a forma ugyanazt a hibaformátumot használja minden végpontra, így a kliensek nem találgatnak (5.3).

Milyen a jó hibaüzenet?

A felhasználónak szóló üzenet négy kérdésre válaszol: mi nem sikerült; milyen következménye van; mit tehet most a felhasználó; és megmaradt-e a munkája. A hangnem legyen nyugodt és pontos.

Gyenge Jobb
„Hiba történt.” „Nem sikerült elmenteni a jelentkezést. Az eddig kitöltött adataid megmaradtak. Ellenőrizd az internetkapcsolatot, majd próbáld újra. Ha a hiba nem szűnik meg, add meg a hibakódot: ABC-123.”
„Rossz adatot adtál meg!” „Az irányítószám öt számjegyből áll.” (a mező mellett)
„Error 500” „Átmeneti hiba lépett fel a mentésnél. Nem történt jelentkezés, nem vontunk le semmit.”

Az üzenet ne hibáztassa a felhasználót, a konkrét, mezőhöz kapcsolt visszajelzés pedig gyorsabban javítható, mint egy általános figyelmeztetés az oldal tetején (9.2). A biztonság is korlát: nyilvános oldalon ne jelenjenek meg adatbázisnevek, fájlútvonalak, belső IP-címek vagy részletes hibanyomkövetések (8. fejezet): ezek támadónak is segítenek. Ezek a részletek a naplóba valók, a felületen a cselekvést segítő összefoglaló.

Az üzenetnek igaznak kell lennie. Ha a fizetési szolgáltató válasza bizonytalan, káros azt írni, hogy „a rendelés biztosan sikertelen”, mert az összeg esetleg mégis levonásra került. Inkább: „A fizetés állapotát még ellenőrizzük. Ne indíts újabb fizetést; hamarosan e-mailben értesítünk.”

Helyreállás és újrapróbálkozás

Nem minden hibára ugyanaz a válasz. Ha a felhasználó elgépelte az e-mail-címét, a rendszer mutassa meg a javítás lehetőségét. Ha rövid hálózati zavar történt, az újrapróbálkozás értelmes lehet. Ha egy pénzügyi tranzakció állapota bizonytalan, az automatikus vagy ismételt beküldés duplázott műveletet okozhat. Ez a 2.3 lecke idempotencia-fogalma a gyakorlatban.

A védekezés egyik módja az idempotenciakulcs: a kliens minden fizetési szándékhoz egyedi kulcsot generál, és minden ismétléssel ugyanazt küldi; a szerver a kulcs alapján felismeri, hogy a kérés már lefutott, és az eredeti eredményt adja vissza. Az IETF HTTPAPI munkacsoportja Idempotency-Key néven fejlécet tervezett erre (jelenleg Internet-Draft, vagyis nem kész szabvány), de a gyakorlatban több szolgáltatás használ hasonló megoldást. A kipróbáló szerveren:

Kulcs nélkül, kétszer elküldve:
  {"tranzakcio":"T1","osszeg":5000}
  {"tranzakcio":"T2","osszeg":5000}        <- kétszer terheltünk

Idempotency-Key: 5f1c-ab12 fejléccel, kétszer elküldve:
  {"tranzakcio":"T3","osszeg":5000}
  {"tranzakcio":"T3","osszeg":5000,"ismetelt":true}   <- egyszer terheltünk

Az újrapróbálkozásra a szerver a Retry-After fejléccel adhat útmutatást (429-nél és 503-nál): másodperceket vagy dátumot adhat meg, amíg a kliensnek várnia kell. Az újrapróbálkozó kliensnek ezt kell követnie, és ismételt hibánál növelnie kell a várakozást, nem korlátlanul, azonnal újrakérnie (10.5).

A jó rendszer a felhasználó munkáját is megőrzi. Hosszú űrlapnál különösen frusztráló, ha egy átmeneti hiba után minden kitöltött mező eltűnik. Az időszakos mentés, a helyi megőrzés (3.6) vagy a szerveroldali vázlat sokat javít az élményen: a hibatűrés nemcsak a szerverek többszörözését jelenti, hanem a felhasználó munkájának védelmét is.

Status page: nyilvános állapot, nem reklámfelület

A status page (szolgáltatásállapot-oldal) külön felület, ahol a szolgáltató tájékoztatja az érdeklődőket a fontos komponensek aktuális állapotáról, a tervezett karbantartásokról és az ismert üzemzavarokról. Különösen értékes, amikor a fő alkalmazás hibás. Ha az állapotoldal ugyanazon a hibás rendszeren fut, éppen akkor lesz elérhetetlen, amikor leginkább szükség lenne rá, ezért érdemes külön infrastruktúrán futtatni.

Egy jó status page komponensekre bontva mutatja például a bejelentkezés, az API, a fájlfeltöltés és a fizetés állapotát; időbélyeges, rövid frissítésekkel írja le, hol tart a hiba (észleltük, vizsgáljuk, azonosítottuk az okát, javítást alkalmazunk, helyreállt, megfigyeljük). Nem kell minden belső részletet nyilvánosságra hozni, de az órákig változatlan „dolgozunk rajta” rombolja a bizalmat. A status page nem váltja ki a közvetlen tájékoztatást azoknál, akiket egy hiba közvetlenül érint (felületen belüli üzenet, e-mail, intézményi csatorna).

Végigvezetett példa: fizetés közben megszakadó kapcsolat a Kurzuspontban

A Kurzuspont egyes kurzusai fizetősek (például egy nyári labor). A hallgató rákattint a „Fizetés” gombra, majd a böngésző kapcsolata megszakad. A képernyő nem tudja biztosan, megtörtént-e a terhelés. Rossz megoldás azonnal azt írni: „Sikertelen fizetés”, és visszaengedni a felhasználót újra fizetni; ugyanilyen rossz automatikusan újraküldeni a tranzakciót.

Lépés Felelős válasz
A kliens a fizetéshez egyedi idempotenciakulcsot küld Az ismétlés nem duplázza a terhelést.
A szerver a kulcs alapján ellenőrzi a tranzakció állapotát Eldönthető, hogy lefutott-e.
Ha bizonytalan 202-vel vagy hasonló jelzéssel közli: feldolgozás alatt.
A felület üzenete „A fizetés állapotát még ellenőrizzük. Ne indíts újabb fizetést. Eredményt e-mailben küldünk.”
Napló Az esemény azonosítója, a kulcs és az idő, jelszó és kártyaadat nélkül.
Status page Ha a fizetési szolgáltató kiesett, ott is szerepel.

Ez egyszerre védi a pénzügyi folyamatot, és csökkenti a felhasználó bizonytalanságát.

Gyakori tévhitek

Állítás Pontosítás
„A részletes technikai hibaüzenet mindig hasznos.” A fejlesztőnek igen, a felhasználónak gyakran nem, és biztonsági kockázat; a részlet a naplóba való.
„Minden 4xx hiba a felhasználó hibája.” A 4xx a kérés problémáját jelzi, de a rossz felület vagy egy elavult kliens is okozhat hibás kérést.
„A status page csak nagy cégeknek kell.” Sok felhasználót érintő, kritikus szolgáltatásnál értékes bizalmi eszköz.
„Az újrapróbálkozás ártalmatlan.” Fizetésnél vagy foglalásnál duplikált műveletet okozhat; idempotenciakulcs kell.
„A hibaüzenet csak szöveg.” A rendszer üzleti és emberi viselkedésének része.

Röviden

  • A hibának három közönsége van: a gép (státuszkód, hibatörzs), a fejlesztő (napló), az ember (üzenet).
  • Az RFC 9457 application/problem+json formátuma egységes, géppel olvasható hibatörzset ad.
  • A jó üzenet megmondja, mi nem sikerült, mi a következménye, mit tehet a felhasználó, és megmaradt-e a munkája; belső részletet nem árul el.
  • Bizonytalan állapotú műveletnél (fizetés) az ismétlés csak idempotenciakulccsal biztonságos.
  • A status page nyilvános, komponensenként frissülő, külön infrastruktúrán futó tájékoztatás.

Ellenőrző kérdések

  1. Mit tartalmaz egy Problem Details hibatörzs?
  2. Miért ne írjuk ki a felhasználónak a hibanyomkövetést?
  3. Hogyan véd az idempotenciakulcs a dupla terheléstől?
  4. Mit kell tartalmaznia egy jó hibaüzenetnek?

Tanulási források

Prerequisites (1)

  • HTTP

Teaches (2)

  • hibakezelés
  • felhasználói hibaüzenet