Stāvokļa uzturēšana Web aplikācijā

Mērķi

  • Saprast, kā dažādi HTTP pieprasījumi dažādās lapās var piekļūt tiem pašiem objektiem
  • Ņemt vērā atmiņas izmantošanas apsvērumus, izmantojot HTTP sesijas
  • Lietot URL pārrakstīšanu (url rewriting)

Kas ir sesija

  • Objekts, kuru veido un uztur Web serveris (konteiners)
  • Kopīgs visiem HTTP pieprasījumiem no tā paša klienta
  • Tiek lietots, lai uzturētu klienta stāvokli (precīzāk, "sarunas stāvokli", komunicējot ar klientu)
  • Šo objektu reprezentē unikāls sesijas ID
  • Pats klients (pārlūkprogramma, utml.) sesiju neredz, bet var novērot blakusefektus, kas netieši norāda uz sesijas izveidošanu: Pārlūkprogrammā nonāk "sesijas cepumiņš", t.i. cepumiņš, kurš dzīvo līdz pārlūkprogrammas aizvēršanai, vai arī pieprasītajai URL adresei galā pierakstās SESSIONID vai tamlīdzīgs parametrs
  • Sesijas izmanto Web aplikācijas komponenti, lai sekotu līdzi dialogam ar dažādajiem lietotājiem, kad tie mijiedarbojas ar Web aplikāciju

HTTP praktiski ir bezstāvokļa protokols (stateless protocol), t.i. katrs lietotāja pieprasījums ir neatkarīgs no citiem pieprasījumiem, un protokola līmenī netiek uzturēts "sarunas stāvoklis". Lai šo problēmu pārvarētu, programmētāji (piemēram, agrīnās Perl'a CGI aplikācijās) veidoja paši savus stāvokļa uzturēšanas risinājumus, piemēram, piekabinot stāvokli URLam, vai noglabājot stāvokli slēptajos formu laukos:

<form action="stuff.pl" method="POST">
...
<input type="hidden" name="SESSIONID" value="4238927426897" />
...
</form>

Praksē tas noveda pie gariem un neērtiem "vienreiz lietojamiem" URLiem. Turklāt, tiklīdz kā dialogs starp klientu un serveri pārtrūka (iespraucās neparedzēts kļūdas paziņojums, vai arī klients pa vidu manuāli pieprasīja cita servera URL), visa sesiju uzturošā informācija pazuda.

Nākamais solis Web aplikāciju stāvokļa uzturēšanā bija "cepumiņu" (cookies) izveidošana (pateicoties Netscape pūlēm) - tie ir īpašs mehānisms informācijas glabāšanai uz klienta mašīnas, lai palīdzētu serverim. Tomēr, ne visas pārlūkprogrammas atbalsta cepumiņus, turklāt klienti var cepumiņu atbalstu atslēgt, vai arī organizāciju ugunsmūri var tos izfiltrēt.

HTTP Servletu specifikācija apraksta vienkāršu risinājumu, kurš atļauj serverim uzglabāt klienta "sarunas stāvokli" starp pieprasījumiem - javax.servlet.http.HttpSession objektu. Servlets var izmantot sesiju, lai glabātu aplikācijai raksturīgus datus, kuriem var piekļūt ikreiz, kad dotais klients atgriežas Web aplikācijā. Katru reizi, kad klients pieprasa kaut ko no aplikācijas, Web serveris to identificē un atrod viņam atbilstošo sesiju. Sesijas dzīves ilgumu var konfigurēt Web servera līmenī.

Katrai sesijai, ko rada Web serveris, ir unikāls sesijas ID. Tas ir atkarīgs no Web konteinera, bet bieži mēdz būt atkarīgs no klienta IP adreses, porta numura, sesijas izveidošanas laika un arī nejauši ģenerētas informācijas.

Sesijas redzamība

Session sharing

Web konteiners uztur sesiju katram klientam. Šī sesija ir kopīgs objekts, ar kuru var darboties visi aplikācijā esošie servleti un JSP. Web'a konteiners nosaka, kura sesija pieder konkrētajam klientam pēc sesijas ID. Sesijas ID tātad nonāk Web serverī kā daļa no klienta pieprasījuma. Pastāv vairākas iespējas, kā klients var šo sesijas ID nodot:

Tipiskākais veids ir uzturēt sesijas ID cepumiņā, kuru uzglabā pārlūkprogramma. Katru reizi, kad klients izdara pieprasījumu tam pašam Web'a domēnam, cepumiņš, kurš satur šo sesijas ID tiks nosūtīts uz Web serveri. Web serveris atpazīs cepumiņu, iegūs no tā sesijas ID, un ja vēl varēs, izvilks sesijas objektu pēc šī ID. Ja klienta pārlūkprogrammā cepumiņi ir atspējoti (disabled), Web konteiners lieto citu metodi - "URL pārrakstīšanu" (URL rewriting).

HttpSession objekta iegūšana

  • JSP lapās vienmēr ir pieejams atbilstoši inicializēts objekts session
  • Servletos sesiju iegūst, izmantojot šādu izsaukumu:
    HttpSession session = request.getSession();
    

Izsaukumam getSession() servleta metodes (doGet() vai doPost()) sākumā ir divi efekti - pirmkārt tas noskaidro, vai sesija jau eksistē, un ja nē, tad izveido sesiju. Ja sesija jau eksistē, tad atgriež jau agrāk eksistējušo sesiju.

Ir arī metode getSession(boolean create), kurai nodod "true" vai "false". "true" gadījumā tā uzvedas tāpat kā bezargumentu getSession(), bet "false" gadījumā tā neveido jaunu sesiju, bet atgriež vai nu agrāk eksistējušo sesiju, vai null, ja sesijas šobrīd nav.

Sesijas dzīvescikls

getSession() atgriež eksistējošu sesiju, kad klienta pieprasījums satur spēkā esošu sesijas ID - vai nu kā cepumiņu, vai kā URL parametru.

getSession() atgriež jaunu sesiju, kad:

  • Tas ir pirmais klienta pieprasījums attiecīgajā domēnā
  • Iepriekšējā sesija ir notecējusi ilgstošas nelietošanas dēļ
  • Servlets ir atklāti invalidējis sesiju
  • Klienta pieprasījums kādu citu iemeslu dēļ nesatur sesijas ID

Sesijas objekti dzīvo Web konteinera iekšpusē uz sesijas dzīves ilgumu (kas ierobežots ar termiņu (timeout)). Šajā laikā servleti var pievienot vai nolasīt informāciju no šīm sesijām.

web.xml failā var norādīt formas autentifikāciju. Šajā gadījumā sesiju izveidos login'a laikā - login'a JSP lapā vai servletā. Visi turpmākie pieprasījumi jau saturēs sesijas ID.

Piekļūšana sesijas datiem

Aplikācijas datus glabā HttpSession objektā kā vārdnīcu (map), kas attēlo vārdus par vērtībām. Piemērs:

Cart cart = (Cart)session.getAttribute("shoppingCart");
if (cart == null) {
    cart = new Cart();
	session.setAttribute("shoppingCart", cart);
}
cart.addItem(item);

Ir šādas HttpSession metodes, kuras ļauj strādāt ar aplikācijas datiem:

void setAttribute(String bindName, Object anyObject)

Metode piesaista objektu sesijai. bindName var lietot, lai šo objektu atkal vēlāk dabūtu.

Object getAttribute(String bindName)

Iegūst objektu, kurš piesaistīts bindName vai null. Šo objektu parasti vajag pārveidot par sākotnējo tipu ar atklātu tipa pārveidojumu.

Enumeration getAttributeNames()

Iegūst visus vārdus, kam sesijā kaut kas piesaistīts. Uz šiem vārdiem var vēlāk saukt getAttribute() metodi.

void remoeAttribute(String bindName)

Aizvāc objektu no sesijas, kurš ir piesaistīts vārdam bindName.

Citas darbības ar sesijām

// atgriezh sessionID
String sessionID = session.getId();

// noraada, ka sesija ir tikko radīta
if (session.isNew()) {
    out.println("This session is new");
}

// invalidee sho sesiju
session.invalidate();

// cita informaacija
out.println("*** Session info:");
out.println("Creation time (millisec):"); 
out.println(session.getCreationTime()); 
out.println("Last accessed (millisec):"); 
out.println(session.getLastAccessedTime());
out.println("Timeout period (seconds):"); 
out.println(session.getMaxInactiveInterval()); 

Piemērs: Ceļojumu aģentūras lapas

Lapā ienāk jauns lietotājs:

HttpSession session = request.getSession(); 
session.setAttribute("it", new Itinerary()); 

Izmaina ceļojuma datus:

HttpSession session = request.getSession();
Itinerary itinerary = (Itinerary)session.getAttribute("it");
itinerary.setDepartureDate("2001-01-01"); 
itinerary.setDepartureAirport("RIX"); 

Parāda ceļojuma datus:

<jsp:usebean id="it" class="travelagency.Itinerary" scope="session"/>
<p>Jūs izlidosiet no lidostas <%= it.getDepartureAirport() %></p>

Sesiju persistence

  • Sesijas dažos Web konteineros var tikt saglabātas pastāvīgajā atmiņā, ja aplikācija ir ļoti noslogota, vai arī kāda no klastera mašīnām beidz darbu (fail over in clustering). Situācija raksturīga, piemēram, WebLogic serveriem.
  • Šādos gadījumos var konfigurēt faila vai datubāzes persistēšanas mehānismu, kā arī veiktspējas parametrus - cik vienlaikus var būt aktīvu sesijas objektu, kāds ir termiņš sesiju notecēšanai (timeout).

Kas ir URL pārrakstīšana?

  • Cepumiņu izmantošana sesiju uzturēšanai ir iespējama tikai tad, ja klients atbalsta cepumiņus
  • Kā alternatīva, sessionID var glabāt arī URLā
  • sessionID izmanto, lai noteiktu pieprasījumus no atsevišķajiem lietotājiem un atrastu tiem atbilstošās sesijas

URL pārrakstīšana ir alternatīvs scenārijs, kas sāk strādāt tad, ja klients neatbalsta sīkdatnes/cepumiņus.


Lapa mainīta 2004-11-15 22:37:53