Obsługa sesji przez serwery webowe w J2EE
8 months, 1 week ago

Zaraz po odesłaniu do nas odpowiedzi serwery WWW zapominają, kim jesteśmy. W wielu przypadkach takie zachowanie jest prawidłowe, niekiedy jednak konieczne jest utrzymywanie pomiędzy klientem a serwerem stanu konwersacyjnego obejmującego wiele żądań. Interfejs API serwletów oferuje nam zadziwiająco proste rozwiązanie tego problemu.

Logika istniejącego obecnie modelu utrzymywania stanu konwersacji sprowadza się do sprawdzania prostego parametru przekazywanego wraz z żądaniem i odsyłanego z odpowiedzią. Tym przekazywanym parametrem jest obiekt identyfikujący klienta - identyfikator sesji. Idea jest prosta: po otrzymaniu pierwszego żądania od klienta, serwer tworzy unikalny, charakterystyczny tylko dla jednego klienta identyfikator sesji (podczas tworzenia nowego obiektu sesji) i zwraca go klientowi wraz z odpowiedzią. Wtedy klient z każdym kolejnym swoim żądaniem odsyła do serwera otrzymany identyfikator. Kontener widząc taki identyfikator, odnajduje odpowiednią sesję i wiąże ją z aktualnym żądaniem. W jaki sposób klient i kontener wymieniają między sobą informacje o identyfikatorze sesji? Najprostszym i najbardziej popularnym sposobem wymiany tego rodzaju identyfikacji są tzw. ciasteczka (nazywane też znacznikami kontekstu klienta). Cały proces identyfikacji przebiega wg następujących kroków:

  • 1. klient wysyła pierwsze żądanie na serwer
  • 2. kontener nie widząc w nagłówku HTTP żadnego ciasteczka identyfikującego sesję, tworzy nowy obiekt sesji (musimy jednak zasygnalizować kontenerowi, że chcemy stworzyć lub wykorzystać istniejącą sesję poleceniem request.getSession() w serwlecie obsługującym żądanie)
  • 3. kontener zwraca klientowi odpowiedź wzbogaconą o nagłówek Set-Cookie: JSESSIONID=367A216783167
  • 4. klient z każdym kolejnym żądaniem wysyła na serwer dodatkowy nagłówek Cookie: JSESSIONID=367A216783167
  • 5. kontener w nagłówku HTTP widząc ciasteczko identyfikujące sesję, odnajduje odpowiednią dla klienta sesję i wiąże ją z żądaniem

Co zrobić, kiedy nasz klient (przeglądarka) nie akceptuje ciasteczek? W takiej sytuacji nasz unikalny identyfikator sesji możemy dodawać do każdego z adresów URL przekazywanego od klienta w postaci atrybutu jsessionid, np.:

<a href="http://localhost:8080/Test/DoSomething.do;jsessionid=6732167AS76788">link</a>

Oczywiście tak zmodyfikowany adres URL możemy otrzymać tylko po stronie serwera, a więc musimy go wysyłać w odpowiedniej postaci do klienta wraz z odpowiedzią. Przypisywanie adresów URL jest uzasadnione tylko wtedy, gdy stosowanie ciasteczek jest niemożliwe i tylko jeśli wymuszamy kodowanie adresów URL w odpowiedziach. Np. kodowanie adresów URL w kodzie serwletu możemy zrealizować w następujący sposób:

response.setContentType("text/html");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
out.println("...");
out.println("<a href="" +
response.encodeURL("/Test.do") + "">kliknij mnie</a>");

Na stronach JSP możemy zaś skorzystać ze znacznika <c:URL> biblioteki JSTL.

W sytuacji, w której konieczne będzie przekazanie żądania na inny adres URL, zamiast korzystać z metody response.sendRedirect() powinniśmy użyć response.encodeRedirectURL("Test.do");

Musimy pamiętać, że kodowanie adresów URL odbywa się automatycznie, ale tylko wtedy, gdy nasz klient nie obsługuje ciasteczek i gdy zakodujemy nasze adresy metodą response.encodeURL(String) lub response.encodeRedirectURL(String).w

API serwletów, w interfejsie HttpServletRequest oprócz metody getSession(), udostępnia nam jeszcze jedną dosyć istotną metodę:

  • public HttpSession getSession(boolean) - ta metoda z parametrem true jest równoważna bezargumentowej metodzie getSession(). Jeśli jednak przekażemy do niej parametr false, będzie to oznaczało, że metoda zwróci albo już istniejącą sesję, albo wartość null, jeśli jeszcze nie istnieje sesja powiązana z danym klientem.

Usuwanie sesji

Sesja może zginąć na cztery sposoby: 

  • po przekroczeniu globalnego dla całej aplikacji limitu czasowego określonego w deskryptorze wdrożenia (czas podajemy w minutach):

<session-config>
     <session-timeout>15</session-timeout>
<session-config>

  • po przekroczeniu limitu czasowego ustawionego przez metodę setMaxInactiveInterval(int)  - czas podajemy w sekundach.
  • po wykonaniu metody invalidate() na obiekcie sesji
  • na skutek awarii

Kluczowe metody interfejsu HttpSession

METODA ZNACZENIE
String getId() Zwraca aktualny identyfikator sesji
boolean isNew() Zwraca wartość true, jeśli klient nie odesłał jeszcze żądania z danym
identyfikatorem sesji
long getCreationTime() Zwraca czas powstania sesji
long getLastAccessedTime() Zwraca czas otrzymania przez kontener ostatniego żądania z danym
identyfikatorem sesji
void setMaxInactivateInterval(int) Ustawia maksymalny czas (wyrażony w sekundach) pomiędzy kolejnymi żądaniami klienta w ramach danej sesji
int getMaxInactiveInterval() Zwraca  maksymalny czas (wyrażony w sekundach) pomiędzy kolejnymi żądaniami klienta w ramach danej sesji
void invalidate() Kończy sesję

 

Śledzenie i migracja sesji

Istnieje dokładnie jeden obiekt ServletContext (reprezentujący kontekst aplikacji) w każdej wirtualnej maszynie Javy. Istnieje też dokładnie jeden obiekt ServletConfig dla każdego serwletu w każdej maszynie wirtualnej Javy. Ale w każdej aplikacji internetowej, niezależnie od liczby JVM, istnieje tylko jeden obiekt HttpSession dla określonego identyfikatora sesji. Obiekty HttpSession wraz z atrybutami są przenoszone pomiędzy JVM. W momencie migracji każda sesja ulega pasywacji i aktywacji. Ponieważ podczas migracji na inną maszynę wirtualną trzeba również przenosić wszystkie atrybuty sesji, a nie możemy mieć gwarancji, że atrybuty zawsze w całości będą serializowane, projektanci specyfikacji serwletów doszli do wniosku, że dobrym rozwiązaniem będzie umożliwienie sygnalizowania atrybutom należącym do sesji, że także one zostaną na moment przeniesione. Sygnalizacja ta może odbywać się w klasie implementującej interfejs HttpSessionActivationListener. Jeśli więc z jakiegoś powodu klasy naszych atrybutów sesji nie będą serializowane, powinniśmy skorzystać z interfejsu HttpSessionActivationListener i w jego metodach zwrotnych (sessionDidActivate(HttpSessionEvent) i sessionWillPassivate(HttpSessionEvent)) przygotować nasze atrybuty do wielkiej przeprowadzki. Ogólnie API serwletów w zakresie sesji udostępnia nam aż cztery interfejsy nasłuchujące:

 

Interfejs Metody Zdarzenie Opis
HttpSessionListener

sessionCreated

sessionDestroyed

HttpSessionEvent Zdarzenia utworzenia i zniszczenia obiektu sesji - typu HttpSession
HttpSessionAttributeListener

attributeAdded

attributeRemoved

attributeReplaced

HttpSessionAttributeEvent Chcemy mieć informację, że w obiekcie sesji dodano, usunięto lub zastąpiono jakiś atrybut
HttpSessionBindingListener

valueBound

valueUnbound

HttpSessionBindingEvent Używamy klasy atrybutu i chcemy, aby obiekty jej typu były informowane o dodaniu lub usunięciu z sesji
HttpSessionActivationListener

sessionDidActivate

sessionWillPassivate

HttpSessionBindingEvent Używamy klasy atrybutu i chcemy, aby obiekty jej typu były informowane o przekazywaniu powiązanych z nimi sesji pomiędzy różnymi maszynami JVM w środowisku rozproszonym

 

 

 


Joanna Dzikowska
Comments
17
Lucid CRM
Customer relationship management and company communication
Lucid Assistance
Customer service center and troubleshooting solutions
Lucid Sale
Sales assistant with custom-made e-commerce platforms
Lucid Mailer
Effective email marketing: newsletters, bulletins, mailing campaigns
Lucid Panel
Software for remote administration of hosting and intranet servers
Copyright © 2002-2011 Spacja.com