Hlavní navigace

Seaside (12)

Pavel Křivánek 23. 5. 2005

Tématem dnešního dílu bude práce s cookies a problematika zpracování výjimek a chyb. Zmíníme se o zasílání varování správci aplikace e-mailem a o předefinovávaní chybových hlášení Seaside.

Cookies jsou jednoduchým prostředkem, kterým může webový server uchovávat na straně uživatele data mezi jednotlivými sezeními. Velmi často se cookies používají k rychlé identifikaci návštěvníka, který se na server nemusí ručně znovu přihlašovat, k nastavování jeho oblíbeného barevné schématu apod.

Seaside samozřejmě cookies podporuje a dovoluje s nimi poměrně pohodlně pracovat. Kvůli programátorsky velice příjemné kontrole toku řízení seasidovských aplikací se ale cookies využívají poměrně málo, a to především k účelům, ke kterým jsou primárně určeny. V jiných prostředích se často používají i pro přenos informací mezi stránkami v rámci jednoho uživatelova sezení. Takto vytvořené aplikace mají problémy, pokud má uživatel cookies v prohlížeči vypnuty.

Vytvoříme si demonstrační komponentu, která bude počítat s tím, že s ní pracuje nějaký definovaný uživatel, jehož jméno si uchovává v instanční proměnné.

WAComponent subclass: #CookiesTest
    instanceVariableNames: 'user'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'CookiesTest' 

Při inicializaci této komponenty předpokládáme, že už s ní uživatel někdy pracoval, a pokusíme se jej pomocí cookies identifikovat. Napřed si ale zjistíme, jestli má uživatel podporu cookies ve svém prohlížeči vůbec aktivovánu. Pokud ji mít nebude, nijak ho to neomezí, pouze bude nucen se identifikovat při začátku každého sezení znovu. Na to, že má coocies vypnuté, ho pomocí dekorátoru přidávajícího zprávu ke komponentě upozorníme.

initialize

    (self session checkForCookies)
        ifTrue: [ self setUserFromCookies ]
        ifFalse: [ self addMessage: 'Varovani: cookies nejsou povoleny' ]. 

Cookies je slovník (třída Dictionary) textových záznamů obsažený v aktivním sezení. My použijeme klíč user a jako hodnotu jméno uživatele. Pokud uživatel přistupuje ke komponentě poprvé, nebude slovník cookies tento klíč obsahovat a instanční proměnná user se naplní nedefinovanou hodnotou.

setUserFromCookies

    | cookies  |
    cookies := self session currentRequest cookies.
    user := cookies at: #user ifAbsent: []. 

Při vlastním vykreslení komponenty se podíváme, jestli jí byl uživatel již přiřazen. Pokud ano, vypíšeme v komponentě jeho jméno. V případě, že uživatel definován není, tzn. že uživatel buď přistupuje poprvé, má vypnutou podporu cookies, nebo platnost předchozí již vypršela, zobrazíme mu přihlašovací dialog tvořený vstupním textovým polem a odesílacím tlačítkem.

renderContentOn: html

    user ifNil: [
        html paragraph: 'Prihlaste se, prosim:'.
        html form: [
            html textInputWithValue: 'zde vlozte sve jmeno' callback: [:name |
                user := name.
                self setCookieForNewUser: name ].
            html submitButton ] ]
    ifNotNil: [
        html paragraph: 'Uzivatel: ', user ]. 

Během přihlášení se pokusíme klíč pro identifikaci uživatele do cookies zapsat. K tomu se používá třída WACookie. Platnost záznamu nastavíme na pět dnů. Při nastavení cookie dojde k obnovení stránky. Pokud se cookie nepodaří korektně nastavit, Seaside negeneruje žádnou chybu.

setCookieForNewUser: userName

    self session redirectWithCookie:
        (WACookie new
            key: #user;
            value: userName;
            expireIn: 5 days;
            yourself). 

Zpracování výjimek a chyb

V Seaside se zpracovávají výjimky a chyby podobně jako v běžných smalltalkovských aplikacích. Některé rozdíly ale lze nalézt.

Jako příklad si vezměme komponentu, která generuje chyby v různých kontextech.

renderContentOn: html

    [
        [ 1/0 ] ifError: [html  text: 'chyba 1'.  ].
        html break.
        html anchorWithAction: [ [ 1/0] ifError: [self inform: 'Nastala chyba 1'] ]
            text: 'chyba 2'.
        html break.
        html anchorWithAction: [
            [self call: VadnaKomponenta new]
                ifError: [self inform: 'Nastala chyba 3'] ]
            text: 'chyba 3'.
        html break.
        html anchorWithAction: [ 1/0 ] text: 'chyba 4'.
    ] ifError: [ self inform: 'chyba aplikace' ]. 

První případ (chyba 1) je ošetřená výjimka při vykreslování komponenty. Tato výjimka je zpracována korektně a do stránky je vepsán informační text.

Ve druhém případě (chyba 2) ošetřujeme výjimku, která nastává v bloku prováděném při kliknutí na odkaz. I v tomto případě dojde ke korektnímu zpracování a uživateli se zobrazí informační dialog.

Obě tyto chyby mají podobný charakter. Jedná se o výjimky, které jsou vyvolány a zpracovány v kontinuálně prováděném kódu v rámci jedné stránky.

Ve třetím případě voláme komponentu, která ve vykreslovací metodě generuje chybu a vzniklou výjimku nijak neošetřuje. Podle uvedeného zápisu bychom předpokládali, že vyvstalá výjimka bude zachycena v jí nadřazené komponentě, tedy že se uživateli vykreslí informační dialog s textem ‚Nastala chyba 3‘. Bohužel se ale místo toho uživateli zobrazí běžná informační stránka Seaside s popisem chyby, výpisem zásobníku volání a s odkazem, který spustí nad procesem s výjimkou standardní debugger v nativním uživatelském rozhraní, což ovšem nemá u serverů běžících na pozadí bez možnosti výstupu na display žádný význam, pokud k image nepřistupujeme přes VNC klienta.

Stejného výsledku se dočkáme i ve čtvrtém případě, kdy v akci odkazu nastane neošetřená výjimka, a to i přesto, že se tuto výjimku snažíme odchytit a zpracovat ve zdánlivě nadřazeném bloku.

Zde lehce prosvítá reálný bezestavový charakter webových aplikací. Výjimky je potřeba ošetřovat tam, kde vzniknou – tedy v rámci zobrazované stránky. O zachycení vzniklých chyb se stará přímo Seaside a ošetřuje je právě vytvořením stránky s popisem chyby.

O zpracování chyb při generování stránek se stará třída WAWalkbackError­Handler. Její hlášení obsahují nejnutnější ladící informace, ale při nasazení hotových aplikací jsou zbytečně obsáhlá, nemají vzhled odpovídající provedení zbytku aplikace a v neposlední řadě představují i nemalé bezpečnostní riziko. Snadno se totiž při popisu objektů mohou dopustit faux pa a zobrazit některé citlivé informace. Hodně nebezpečný je například výpis kolekcí. Omezovat kvůli tomu popisné řetězce objektů (metoda printOn:) není právě vhodné řešení, protože při programování naopak vyžadujeme, aby jejich popis byl co nejkomplexnější.

Problém bezpečnosti lze vyřešit tak, že Seaside definujeme, aby použila jinou standardní třídu pro zpracování chyb pojmenovanou WASimpleError­Handler. Ta vypíše pouze nadpis Internal Error a doplní jej stručným textovým popisem.

Změna třídy, která se má použít pro zpracování neošetřených výjimek, se provádí v konfiguraci aplikace pod položkou Error Handler. Samozřejmě je lépe tuto informace nastavit přímo při registraci vaší aplikace, tedy například v inicializační metodě její kořenové komponenty, než tak učinit přes webové rozhraní.

initialize

    | app |
    app := self registerAsApplication: 'Obchod'.
    app preferenceAt: #errorHandler put: WASimpleErrorHandler. 

Tím samozřejmě nevyřešíme vzhledovou konzistenci. Uživateli se zobrazí pouze velmi strohá bílá stránka. Pokud se rozhodnete ji změnit, stačí si vytvořit novou třídu jako potomka třídy WAErrorHandler po vzoru těch již existujících. Konkrétně je třeba upravit metody handleError: respektive handleWarning:. Bohužel v této fázi ošetřování výjimek již přicházíte skoro o všechny výhody, které Seaside nabízí, a budete se pravděpodobně muset spokojit s pouhou ručně vygenerovanou statickou stránkou. Následkem toho může být problematické (nicméně řešitelné) použití stejných stylů, jako má zbytek vaší dynamicky generované aplikace.

Není nutné zůstat u pouhého výpisu chybového hlášení uživateli. Podobné neošetřené výjimky je velmi vhodné logovat, ukládat do databáze, nechávat si posílat informační e-maily apod.

SMTPClient
    deliverMailFrom: 'seaside@seaside.tk'
    to: (Array with: 'administrator@seaside.tk')
    text: 'From: Seaside
Subject: Application error

Error description'
usingServer: 'smtp.server.com' 

Stránky s chybami, jako je např. vypršení platnosti stránky, už tak lehce předefinovat nejdou. Programátor má dvě možnosti. Buď příslušné metody modifikuje přímo v Seaside, což je nejjednodušší řešení, nebo se pokusí o čistší přístup a zainteresované třídy a metody přetíží.

WAApplication subclass: #MyApp
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Store'


handleExpiredRequest: aRequest

    ^ WAResponse new nextPutAll: '<html>
        <head><title>Platnost stranky vyprsela</title></head>

        <body><h1>Platnost stranky vyprsela</h1>
        </body></html>' 

Protože Seaside nepředpokládá, že bude místo WAApplication použita jiná třída, je potřeba u kořenové komponenty, z níž se bude komponenta registrovat, vytvořit následující třídní metodu:

applicationWithPath: aString

    | app |
    app := MyApp path: aString.
    app configuration addAncestor: WARenderLoopConfiguration localConfiguration.
    app preferenceAt: #rootComponent put: self.
    ^ app 

Náš seriál se již nezadržitelně blíží ke konci. Příště nás čeká poslední díl, kde se krátce zmíníme o živých akcích, češtině a dalších tématech, na která se v předchozích dílech nedostalo.

Našli jste v článku chybu?

23. 5. 2005 16:49

Session je identifikována parametrem _s v ulr, např. _s=MYInZQgAUcmcEvca

23. 5. 2005 16:23

Kdyz seaside nepouziva cookie k udrzovani session, co teda pouziva ? IP uzivatele ? HTTP_REFERRER ? GET/POST parametry ?
Lupa.cz: EET v e-shopech? Zdražení a horší komfort

EET v e-shopech? Zdražení a horší komfort

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Vitalia.cz: Manželka je bio, ale na sex moc není

Manželka je bio, ale na sex moc není

Podnikatel.cz: Alza.cz má StreetShop. Mall.cz více výdejních míst

Alza.cz má StreetShop. Mall.cz více výdejních míst

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

Vitalia.cz: Dáte si jahody s plísní?

Dáte si jahody s plísní?

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

120na80.cz: Horní cesty dýchací. Zkuste fytofarmaka

Horní cesty dýchací. Zkuste fytofarmaka

Podnikatel.cz: Babiš: E-shopy z EET možná vyjmeme

Babiš: E-shopy z EET možná vyjmeme

Vitalia.cz: Baletky propagují zdravotní superpostel

Baletky propagují zdravotní superpostel

Lupa.cz: Teletext je „internetem hipsterů“

Teletext je „internetem hipsterů“

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky