Le protocole HTTP est un protocole non connecté
(on parle aussi de protocole sans états, en anglais stateless protocol), cela signifie que chaque requête
est traitée indépendamment des autres et qu'aucun historique des
différentes requêtes n'est conservé. Ainsi le serveur web ne peut pas se "souvenir"
de la requête précédente, ce qui est dommageable dans des utilisations
telles que le e-commerce, pour lequel le serveur doit mémoriser les achats de l'utilisateur
sur les différentes pages.
Il s'agit donc de maintenir la cohésion entre l'utilisateur et la requête, c'est-à-dire :
- reconnaître les requêtes provenant du même utilisateur
- associer un profil à l'utilisateur
- connaître les paramètre de l'application (nombre de produits vendus, ...)
On appelle ce mécanisme de gestion des états le suivi de session (en anglais session tracking).
Il existe une méthode (pouvant se décliner en plusieurs variantes) permettant d'assurer le suivi de session :
Elle consiste à stocker les informations concernant l'utilisateur sur le serveur, et de les relier à chaque
requête grâce à un identifiant (généralement appelé id) présent dans la requête et sur le serveur.
Il existe plusieurs façons standards (utilisées dans tous les types de technologies côté serveur) de passer l'identifiant en paramètre
dans la requête :
- en échangeant des données d'identification du client entre chaque requête
- en ajoutant à l'URL des variables d'identification
- en passant en paramètre un champ de formulaire caché
- en utilisant les cookies
- en demandant l'identification de l'utilisateur à chaque requête
Les informations concernant l'utilisateur sont stockées sur le serveur dans un objet
persistant, nommé HttpSession. Il permet de stocker les informations saisies au fur et
à mesure par l'utilisateur et de les relier à chaque requête grâce à
l'identifiant passé en paramètre.
Il est commun dans le langage e-business de faire l'analogie avec un caddie (parfois shopping cart ou shopping basket) pour désigner ce
système de suivi de session.
La méthode de réécriture d'URL consiste à passer
des paires clé/valeur en paramètre dans l'URL. Ainsi, en passant en paramètre
un identificateur unique de session, il est possible de le relier aux données stockées sur le serveur.
Toutes les URL dans les pages web du serveur ressembleront donc à quelque chose comme ceci (dans cet exemple purement fictif, l'id de session est 674684641):
<a href="http://serveur/servlet/exemple?id=674684641">Lien hypertexte</a>
Ainsi avec cette technique, toutes les pages du site doivent contenir uniquement des URL dont l'ID de session a été ajouté
dynamiquement, ce qui signifie que toutes les pages du site doivent être dynamiques.
D'autre part, étant donné que l'URL est limitée en longueur (255 caractères), il se peut qu'une partie
des informations codées dans l'URL disparaissent. Enfin, bien que les sessions soient
généralement limitées dans le temps (elles expirent), il se peut qu'un utilisateur tiers accède aux données
de l'utilisateur à l'aide de l'URL.
La technique consistant à passer en paramètre un champ de formulaire
contenant l'identifiant de session est similaire, à la différence près
que les données sont envoyées par la méthode POST (plus sûre) :
<Input type="hidden" name="id" value="674684641">
Cette méthode implique par contre l'utilisation systèmatique d'un formulaire
(clic sur un bouton submit) pour passer d'une page à une autre).
Les cookies sont des petits fichiers textes stockés
sur le disque du client, permettant de stocker des paires clés/valeur.
Le cookies concernant le domaine du site sur lequel un utilisateur surfe sont automatiquement envoyés dans les
en-têtes HTTP lors de chaque requête du client.
D'autre part, lorsque le serveur désire créer un cookie sur le navigateur du client,
il lui suffit d'envoyer des instructions dans les en-têtes de la réponse HTTP.
Le JSDK fournit une classe permettant de gérer de façon transparente les cookies,
il s'agit de la classe Cookie.
Ainsi il est possible de stocker un identifiant de session de la manière suivante :
// Creation du cookie
Cookie C = new Cookie("id","674684641");
// definition de la limite de validite
C.setMaxAge(24*3600);
// envoi du cookie dans la reponse HTTP
res.addCookie(C);
Ce mécanisme est le plus intéressant pour stocker de petites informations.
Toutefois l'utilisation de cookies pose quelques problèmes :
- des utilisateurs désactivent les cookies par crainte
- certains anciens navigateurs ne gèrent pas les cookies
L'objet HttpSession permet de mémoriser les données de l'utilisateur, grâce
à une structure similaire à une table de hachage,
permettant de relier chaque id de session à l'ensemble des informations relatives
à l'utilisateur.
Ainsi en utilisant un mécanisme tel que les cookies (permettant d'associer une requête à
un id) et l'objet HttpSession (permettant de relier des informations relatives à l'utilisateur à
un id), il est possible d'associer facilement une requête aux informations de session !
L'objet HttpSession s'obtient grâce à la méthode getSession()
de l'objet HttpServletRequest.
La gestion des sessions se fait de la manière suivante :
- Obtenir l'ID de session
- Si GET: en regardant dans la requête
- Si POST: en regardant dans les en-têtes HTTP
- Sinon dans les cookies
- Vérifier si une session est associé à l'ID
- Si la session existe, obtenir les informations
- Sinon
- Générer un ID de Session
- Si le navigateur du client accepte les cookies, ajouter un cookie contenant l'ID de session
- Sinon ajouter l'ID de session dans l'URL
- Enregistrer la session avec l'ID nouvellement créé
La méthode getSession() de l'objet HttpServletRequest permet de retourner
la session relative à l'utilisateur (l'identification est faite de façon transparente
par cookies ou réécriture d'URL):
HttpSession getSession(boolean create)
L'argument create permet de créer une session relative à la requête
lorsqu'il prend la valeur true.
|
Etant donnée que les cookies sont stockés dans le en-têtes HTTP, et que celles-ci doivent être
les premières informations envoyées, la méthode getSession() doit être appelée avant tout envoi de données
au navigateur (la méthode doit être invoquée avant toute écriture sur le flot de sortie de la servlet)
|
L'exemple suivant récupère la session associée à la requête de l'utilisateur
et la crée si elle n'existe pas déjà :
public class Caddie extends HttpServlet {
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
...
// Ecrit la reponse
out = response.getWriter();
...
}
}
Pour obtenir une valeur précédemment stockée dans l'objet
HttpSession, il suffit d'utiliser la méthode getAttribute()
de l'objet HttpSession (celle-ci remplace dans la version 2.2 de l'API servlet la méthode getValue()
qui était utilisée dans les versions 2.1 et inférieures).
Object getAttribute("cle")
La méthode getAttribute() retourne un objet (de type Object),
il faut donc effectuer un surtypage pour obtenir un type élémentaire
de données (un entier sera renvoyé sous forme d'objet Integer
qu'il faudra convertir en int).
Si l'attribut passé en paramètre n'existe pas, la méthode getAttribute()
retourne la valeur null.
public class Caddie extends HttpServlet {
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
// Recupere l'age de l'utilisateur
Age = (int)session.getAttribute("Age");
if (Age != null) {
// ... faire quelque chose
// Ecrit la reponse
out = response.getWriter();
}
else {
Age = new Integer(...);
// ... faire quelque chose d'autre
// Ecrit la reponse
out = response.getWriter();
}
}
}
Le stockage d'informations dans la session est similaire à la lecture.
Il suffit d'utiliser la méthode setAttribute() (putvalue()
pour les versions antérieures à la 2.2) en lui fournissant comme
attributs la clé et la valeur associée.
Object setAttribute("cle","valeur")
L'exemple suivant stocke dans la session la page d'appel de la servlet (une page ayant
fait un lien), ainsi que la date du dernier accès :
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Caddie extends HttpServlet {
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
// Recupere l'age de l'utilisateur
session.setAttribute("referer",request.getHeader("Referer"));
}
}
D'une manière générale, il est préférable de laisser
une session se terminer seule (par expiration par exemple). Cependant, dans certains cas
il peut être utile de supprimer manuellement une session (si l'utilisateur achète
le contenu du caddie par exemple). Pour supprimer une session, il suffit de faire appel
à la méthode invalidate() de l'objet HttpSession
public class Caddie extends HttpServlet {
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
session.invalidate();
}
}
Méthode |
Description |
long getCreationTime()( |
Retourne l'heure de la création de la session |
Object getAttributes(String Name) |
Retourne l'objet stocké dans la session sous le nom Name, null s'il n'existe pas |
String getId() |
Génère un identifiant de session |
long getCreationTime()( |
Retourne la date de la requête précédente pour cette session |
String[] getValueNames()( |
Retourne un tableau contenant le nom de toutes les clés de la session |
Object getValue(String Name) |
Retourne l'objet stocké dans la session sous le nom Name, null s'il n'existe pas |
void invalidate() |
Supprime la session |
boolean isnew()( |
Retourne true si la session vient d'être créée, sinon false |
void putValue(String Name, Object Value) |
Stocke l'objet Value dans la session sous le nom Name |
void removeValue(String Name) |
Supprime l'élément Name de la session |
void setAttribute(String Name, Object Value) |
Stocke l'objet Value dans la session sous le nom Name |
int setMaxInactiveInterval(int interval) |
Définit l'intervalle de temps maximum entre deux requête avant que la session n'expire |
int getMaxInactiveInterval(int interval) |
Retourne l'intervalle de temps maximum entre deux requête avant que la session n'expire |
|