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
- Mit tartalmaz egy Problem Details hibatörzs?
- Miért ne írjuk ki a felhasználónak a hibanyomkövetést?
- Hogyan véd az idempotenciakulcs a dupla terheléstől?
- Mit kell tartalmaznia egy jó hibaüzenetnek?
Tanulási források
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/403a hitelesítés és a jogosultság különbségét, a429a sebességkorlátozást, a502/503/504az á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+jsonmédiatípusú JSON-törzs ezeket a tagokat tartalmazhatja:typeabout:blank, vagyis a státuszkódon túl nincs külön jelentése.titlestatusdetailinstanceA 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):
A kliens a
typealapján dönti el, mit tegyen (például felkínál másik kurzust); adetailemberi 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.
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-Keyné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:Az újrapróbálkozásra a szerver a
Retry-Afterfejléccel adhat útmutatást (429-nél és503-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.
202-vel vagy hasonló jelzéssel közli: feldolgozás alatt.Ez egyszerre védi a pénzügyi folyamatot, és csökkenti a felhasználó bizonytalanságát.
Gyakori tévhitek
Röviden
application/problem+jsonformátuma egységes, géppel olvasható hibatörzset ad.Ellenőrző kérdések
Tanulási források