<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://openweb.eu.org/dtd/docbkx42/docbookx.dtd">
<article role="article" xml:lang="fr" lang="fr" id="objet_xmlhttprequest">
	<articleinfo>
		<title>L'objet XMLHttpRequest</title>
		<pubdate>2005-04-21</pubdate>
		<date>2005-04-21</date>
		<author>
			<firstname>Maurice</firstname>
			<surname>Svay</surname>
		</author>
		<subjectset>
			<subject role="profil">
				<subjectterm>expert</subjectterm>
				<subjectterm>gourou</subjectterm>
			</subject>
			<subject role="technologie">
				<subjectterm>dom</subjectterm>
			</subject>
			<subject role="theme">
				<subjectterm>pages_dynamiques</subjectterm>
			</subject>
		</subjectset>
		<abstract>
			<para>De nouvelles applications web ont vu le jour récemment: recherche avec complétion automatique, sauvegarde instantanée d'informations, interface mail hyperdynamique, cartographie, etc. mais aucune ne fait appel à des plugins tiers comme Flash ou Java. On parle alors souvent de méthode AJAX qui s'articule essentiellement autour de Javascript et d'un objet (dans le sens de la programmation orientée objets) en particulier: XMLHttpRequest.</para>
		</abstract>
	</articleinfo>
	  	<para>Créé par Microsoft pour Internet Explorer, l'objet XMLHttpRequest a été adopté par les navigateurs Mozilla, Konqueror, Safari et récemment Opéra. Bien que largement implémentée dans les navigateurs récents, <emphasis role="strong">cette technologie n'est pas un standard du <acronym>W3C</acronym></emphasis>, lequel propose des fonctionnalités similaires à travers la recommandation <ulink url="http://www.w3.org/TR/DOM-Level-3-LS/">Document Object Model (<acronym>DOM</acronym>) Level 3 Load and Save Specification</ulink>.</para>
	  	<para>Cet objet permet de faire des requêtes <acronym>HTTP</acronym> afin de récupérer des données au format <acronym>XML</acronym> qui pourront être intégrées à un document. Cela peut être très utile pour mettre à jour des données sans pour autant recharger la page.</para>
	  	<para>Les avantages possibles :</para>
			<itemizedlist>
      	<listitem>
        	<para>Diminution de la bande passante : seules les données sont chargées et non plus tout le document ;</para>
      	</listitem>
      	<listitem>
        	<para>Interactivité accrue : plus de rechargement de la page ;</para>
      	</listitem>
      	<listitem>
        	<para>Rationnalisation du code : des routines (de vérification par exemple) n'ont plus à être écrites et maintenues dans deux langages (côté client et côté serveur).</para>
      	</listitem>
  	</itemizedlist>
	  <para>Les inconvénients possibles :</para>
		<itemizedlist>
      <listitem>
        <para>Ne fonctionne pas sans Javascript, ni dans les navigateurs les plus anciens ;</para>
      </listitem>
      <listitem>
        <para>Ne fonctionne qu'avec <acronym>HTTP</acronym> : il est impossible de récupérer des données sur un disque local (ce qui est normal) ;</para>
      </listitem>
      <listitem>
        <para>Les requêtes en dehors du domaine provoquent un avertissement de sécurité ;</para>
      </listitem>
			<listitem>
				<para>Peut empêcher des comportements habituels du navigateur :</para>
				<itemizedlist>
      		<listitem>
        		<para>Marques-pages et liens vers la page ;</para>
      		</listitem>
      		<listitem>
        		<para>Enregistrement des pages ;</para>
      		</listitem>
      		<listitem>
        		<para>Bouton retour.</para>
      		</listitem>
				</itemizedlist>
			</listitem>
  	</itemizedlist>
	<section>
		<title>Une architecture client-serveur</title>
  	<para>L'objet XMLHttpRequest s'utilise dans une architecture de type client/serveur. Le navigateur avec son moteur Javascript va faire office de client. Du côté du serveur, n'importe quelle application délivrant du <acronym>XML</acronym> à travers <acronym>HTTP</acronym> fait l'affaire. La communication entre les deux peut se faire suivant deux modes : synchrone ou asynchrone. Dans le premier cas, les traitements suivant une requête ne sont exécutés que lorsque celle-ci est terminée. Dans le second cas, les traitements sont exécutés sans attendre son résultat. C'est ce dernier cas qui est intéressant pour créer des applications interactives et dynamiques. Détaillons son mode de fonctionnement :</para>
  	<itemizedlist>
    	<listitem>
      	<para>L'objet XMLHttpRequest est créé. Un gestionnaire de réponse lui est associé.</para>
    	</listitem>
    	<listitem>
      	<para>Il est alors utilisé pour créer et effectuer une requête <acronym>HTTP</acronym>.</para>
    	</listitem>
    	<listitem>
      	<para>Sans attendre le résultat, le reste des instructions est exécuté. Les instructions déclenchées par une réponse du serveur seront exécutées par le gestionnaire défini plus haut dès que le navigateur aura reçu une réponse.</para>
    	</listitem>
		</itemizedlist>
		<section>
			<title>Note à propos d'<acronym>AJAX</acronym></title>
			<para>L'utilisation de XMLHttpRequest fait immédiatement penser à <acronym>AJAX</acronym> (Asynchronous JAvascript <acronym>XML</acronym>). Cette architecture client/serveur consiste en effet à découper une application web de la façon suivante :</para>
    	<itemizedlist>
      	<listitem>
        	<para>une présentation utilisant <acronym>XHTML</acronym> et <acronym>CSS</acronym> ;</para>
      	</listitem>
      	<listitem>
        	<para>la manipulation dynamique des pages à travers <acronym>DOM</acronym> ;</para>
      	</listitem>
      	<listitem>
        	<para>la manipulation des données avec <acronym>XML</acronym> et <acronym>XSLT</acronym> ;</para>
      	</listitem>
      	<listitem>
        	<para>l'échange des données de manière asynchrone avec XMLHttpRequest ;</para>
      	</listitem>
      	<listitem>
        	<para>le tout étant assemblé avec du Javascript.</para>
      	</listitem>
    	</itemizedlist>
			<para>Les éléments clés de cette architecture sont la séparation en couches distinctes des éléments du client à l'aide de technologies standardisées et les échanges asynchrones de données au format <acronym>XML</acronym>. L'objet dont il est question dans cet article est un élément central, car c'est lui qui permet la communication entre le client et le serveur.</para>
		</section>
	</section>
	<section>
		<title>De la théorie à la pratique</title>
  	<section>
  		<title>Côté client, l'objet Javascript XMLHttpRequest</title>
  		<para>L'objet n'étant pas standardisé, son implémentation varie légèrement selon les navigateurs. Alors que Microsoft dispose des fonctions <token>ActiveXObject("Msxml2.XMLHTTP")</token> et <token>ActiveXObject("Microsoft.XMLHTTP")</token>, selon le moteur <acronym>XML</acronym> utilisé, les autres navigateurs utilisent simplement la fonction <token>XMLHttpRequest()</token>. </para>
  		<para>Pour obtenir un objet lorsqu'il est disponible, il est inutile de faire des tests sur l'identité du navigateur : il suffit en effet de vérifier directement la disponibilité des fonctions. Le code suivant est une fonction qui renvoie l'objet <token>XMLHttpRequest</token> ou la valeur <token>false</token> lorsque le navigateur ne dispose pas de cette fonctionnalité. C'est aussi dans cette fonction qu'est défini le gestionnaire de changement d'état.</para>
<programlisting>
function getHTTPObject()
{
  var xmlhttp = false;

  /* Compilation conditionnelle d'IE */
  /*@cc_on
  @if (@_jscript_version &gt;= 5)
     try
     {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
     }
     catch (e)
     {
        try
        {
           xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (E)
        {
           xmlhttp = false;
        }
     }
  @else
     xmlhttp = false;
  @end @*/

  /* on essaie de créer l'objet si ce n'est pas déjà fait */
  if (!xmlhttp &amp;&amp; typeof XMLHttpRequest != 'undefined')
  {
     try
     {
        xmlhttp = new XMLHttpRequest();
     }
     catch (e)
     {
        xmlhttp = false;
     }
  }

  if (xmlhttp)
  {
     /* on définit ce qui doit se passer quand la page répondra */
     xmlhttp.onreadystatechange=function()
     {
        if (xmlhttp.readyState == 4) /* 4 : état "complete" */
        {
           if (xmlhttp.status == 200) /* 200 : code HTTP pour OK */
           {
              /*
              Traitement de la réponse.
              Ici on affiche la réponse dans une boîte de dialogue.
              */
              alert(xmlhttp.responseText);
           }
        }
     }
  }
  return xmlhttp;
}
</programlisting>
  		<para>La première partie de la fonction utilise une syntaxe particulière spécifique à Internet Explorer. La seconde partie s'adresse aux autres navigateurs. La troisième partie permet de définir le gestionnaire d'événement qui traitera la réponse.</para>
  	</section>
  	<section>
  		<title>Utiliser cet objet : propriétés et méthodes</title>
  		<para>Une fois créé, l'objet peut être manipulé à travers ses propriétés et méthodes :</para>
        <table>
           <title>Les propriétés de l'objet XMLHttpRequest</title>
           <tgroup cols="">
             <thead>
             	<row>
             		<entry>Propriété</entry>
             		<entry>Description </entry>
             	</row>
             </thead>
             <tbody>
             	<row>
             		<entry><token>onreadystatechange</token></entry>
            			<entry>Gestionnaire d'événements pour les changements d'état. Il faut assigner une fonction à cette propriété pour effectuer des traitements sur les données renvoyées après la requête.</entry>
            		</row>
            		<row>
              		<entry><token>readyState</token></entry>
             			<entry>statut de l'objet.</entry>
             		</row>
             		<row>
             			<entry><token>responseText</token></entry>
             			<entry>Réponse sous forme de chaîne de caractères.</entry>
             		</row>
             		<row>
             			<entry><token>responseXML</token></entry>
             			<entry>Réponse sous forme d'objet <acronym>DOM</acronym>.</entry>
             		</row>
             		<row>
             			<entry><token>status</token></entry>
             			<entry>code numérique de réponse du serveur <acronym>HTTP</acronym></entry>
             		</row>
             		<row>
             			<entry><token>statusText </token></entry>
             			<entry>message accompagnant le code de réponse.</entry>
             		</row>
             	</tbody>
           	</tgroup>
           </table>
  				<para>Les code possibles pour le statut de l'objet sont :</para>
       		<itemizedlist>
           	<listitem>
             	<para>0 = non initialisé ;</para>
           	</listitem>
           	<listitem>
             	<para>1 = ouverture. La méthode <token>open()</token> a été appelée avec succès ;</para>
           	</listitem>
           	<listitem>
             	<para>2 = envoyé. La méthode <token>send()</token> a été appelée avec succès ;</para>
           	</listitem>
           	<listitem>
             	<para>3 = en train de recevoir. Des données sont en train d'être transférées, mais le transfert n'est pas terminé ;</para>
           	</listitem>
           	<listitem>
             	<para>4 = terminé. Les données sont chargées.</para>
           	</listitem>
         	</itemizedlist>
       		<table>
           	<title>Les méthodes de l'objet XMLHttpRequest et leurs paramètres</title>
           	<tgroup cols="">
             	<thead>
             		<row>
             			<entry>Méthode</entry>
             			<entry>Paramètres</entry>
             			<entry>Description</entry>
             		</row>
             	</thead>
             	<tbody>
             		<row>
             			<entry><token>abort</token></entry>
             			<entry><token>()</token></entry>
             			<entry>Abandonne la requête.</entry>
             		</row>
             		<row>
             			<entry><token>getAllResponseHeaders</token></entry>
             			<entry><token>()</token></entry>
             			<entry>Renvoie l'ensemble de l'entête de la réponse sous forme de chaîne de caractères.</entry>
             		</row>
             		<row>
             			<entry><token>getResponseHeader</token></entry>
             			<entry><token>("champEntete")</token></entry>
             			<entry>Renvoie la valeur d'un champ d'entête <acronym>HTTP</acronym>.</entry>
             		</row>
             		<row>
             			<entry><token>open </token></entry>
             			<entry><token>("method", "URL"[, asyncFlag[, "userName"[, "password"]]])</token></entry>
             			<entry>Prépare une requête en indiquant la méthode, l'<acronym>URL</acronym>, la drapeau de synchronisation, le nom d'utilisateur et le mot de passe.</entry>
             		</row>
             		<row>
             			<entry><token>send</token></entry>
             			<entry><token>(contenu)</token></entry>
             			<entry>Effectue la requête, éventuellement en envoyant les données.</entry>
             		</row>
             		<row>
             			<entry><token>setRequestHeader</token></entry>
             			<entry><token>("champ", "valeur")</token></entry>
             			<entry>Assigne une valeur à un champ d'entête <acronym>HTTP</acronym> qui sera envoyé lors de la requête.</entry>
             		</row>
             	</tbody>
           	</tgroup>
           </table>
 			</section>
			<section>
				<title>Faire une requête</title>
				<para>On considère qu'un gestionnaire d'événement a été assigné à la propriété <token>onreadystatechange</token>. Voici quelques exemples de requêtes courantes avec les méthodes <token>HEAD</token>, <token>GET</token> et <token>POST</token> :</para>
  			<section>
  				<title>Une requête de type <token>HEAD</token></title>
<programlisting>
/* Création de l'objet : */
var xmlhttp = getHTTPObject();
/* Préparation d'une requête asynchrone de type HEAD : */
xmlhttp.open("HEAD", "/test.html",true); 
/* Effectue la requête : */
xmlhttp.send(null);
</programlisting>
  			</section>
  			<section>
  				<title>Une requête de type <token>GET</token></title>
<programlisting>
/* Création de l'objet : */
var xmlhttp = getHTTPObject(); 
/* Préparation d'une requête asynchrone de type GET : */
xmlhttp.open("GET", "/test.php?var1=valeur1&amp;var2=valeur2",true); 
/* Effectue la requête : */
xmlhttp.send(null); 
</programlisting>
  			</section>
  			<section>
  				<title>Une requête de type <token>POST</token></title>
<programlisting>
/* Création de l'objet : */
var xmlhttp = getHTTPObject();
/* Préparation d'une requête asynchrone de type POST : */
xmlhttp.open("POST", "/test.php",true);
/* Effectue la requête en envoyant les données : */
xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xmlhttp.send("var1=valeur1&amp;var2=valeur2");
</programlisting>
  			</section>
		</section>
		<section>
			<title>Côté serveur</title>
			<para>Côté serveur, le programmeur est libre. Quels que soient le langage utilisé (<acronym>PHP</acronym>, <acronym>ASP</acronym>, Java, etc.) et les traitements effectués, il suffit de ne renvoyer que les informations nécessaires sous forme de flux <acronym>XML</acronym>.</para>
		</section>
	</section>
	<section>
		<title>Exemple concret, identification à travers XMLHttpRequest</title>
		<para>Maintenant que nous avons vu comment utiliser l'objet XMLHttpRequest, nous allons voir comment le mettre en application à travers un exemple simple: l'identification d'un utilisateur. Nous allons mettre en place un formulaire permettant à un utilisateur de se connecter avec un identifiant et un mot de passe. Notre objectif est de rendre cette connexion plus interactive dans l'affichage de la réussite ou de l'échec de la transaction. C'est pourquoi, contrairement à un formulaire classique où les données seraient envoyées pour obtenir une page de réponse, notre formulaire sera enrichi avec XmlHttpRequest pour que l'utilisateur sache immédiatement s'il est connecté ou non, dès qu'il aura cliqué sur le bouton de validation.</para>
		<section>
			<title>Structure générale de l'application</title>
      <mediaobject>
       	<imageobject>
       		<imagedata fileref="annexes/structure-identification.png" />
       	</imageobject>
       	<textobject>
       		<phrase></phrase>
       	</textobject>
       </mediaobject>
			 <para>La structure d'une application utilisant XMLHttpRequest <emphasis role="strong">doit</emphasis> prendre en compte qu'il n'est pas toujours possible de l'utiliser et donc <emphasis role="strong">prévoir une solution de repli</emphasis>.</para>
			 <para>Dans notre exemple, il y a deux moyens de faire passer les informations d'identification :</para>
				<itemizedlist>
        	<listitem>
          	<para>par la voie classique avec un envoi du formulaire à un script qui répond par une page Web (la partie gauche sur le schéma)</para>
        	</listitem>
        	<listitem>
          	<para>à travers XMLHttpRequest qui envoie les données et reçoit la réponse du serveur (à droite sur le schéma)</para>
        	</listitem>
  			</itemizedlist>
				<para>Habituellement, les données transiteront grâce aux fonctions de l'objet XMLHttpRequest. Ce type d'échange rend la page web moins contraignante, car elle n'est pas rechargée à chaque action. Le formulaire peut alors servir à des actions évoluées (saisie avec vérification instantanée, prise en compte immédiate d'actions, etc.).</para>
        <para>Cependant, il est possible que l'objet XMLHttpRequest ne soit pas disponible ( car non supporté par le navigateur par exemple) ou que l'exécution de code Javascript soit totalement impossible (fonctionnalité désactivée ou absente de l'agent utilisateur).</para>
        <para>Dans ce cas, le formulaire retrouve son comportement habituel qui consiste à collecter des informations et à les envoyer au serveur pour les traiter. En contrepartie, le serveur génère une page Web qui indique le résultat du traitement. Cette méthode constitue la solution de secours si la première n'est pas disponible.</para>
        <para>Ce point est important lorsque cette technologie est utilisée sur un site Web. On ne peut alors pas prévoir les capacités du client utilisé. La création d'une méthode de repli peut éventuellement être ignorée si l'environnement est connu ( dans un intranet par exemple) mais il faut savoir que le surcoût de développement est minime si l'application est correctement architecturée.</para>

		</section>
		<section>
			<title>Plongée dans le code</title>
			<section>
				<title>identification.html, c'est par là que tout commence</title>
			 <para>Le fichier identification.html est la page que l'utilisateur consulte. Elle est simplement constituée d'un formulaire permettant la saisie d'une login et d'un mot de passe. C'est également à partir de cette page qu'on appelle le code Javascript qui se trouve dans identification.js.</para>
<programlisting>
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
 &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"&gt;
 &lt;head&gt;
    &lt;meta http-equiv="Content-Type" content="text/HTML; charset=iso-8859-15" /&gt;
    &lt;meta http-equiv="Content-Script-Type" content="text/javascript" /&gt;
    &lt;meta http-equiv="Content-Language" content="fr" /&gt;

    &lt;title&gt;Identification avec XmlHttpRequest?&lt;/title&gt;
    &lt;script type="text/javascript" src="identification.js"&gt;&lt;/script&gt;
 &lt;/head&gt;

 &lt;body&gt;
    &lt;form action="identification.php" method="get" id="frmIdentification"&gt;
        &lt;fieldset&gt;
            &lt;legend&gt;Connexion&lt;/legend&gt;

            &lt;label for="txtLogin"&gt;Login&lt;/label&gt;
            &lt;input type="text" value="" name="login" id="txtLogin" /&gt;

            &lt;label for="txtPassword"&gt;Mot de passe&lt;/label&gt;
            &lt;input type="text" value="" name="password" id="txtPassword" /&gt;

            &lt;input type="submit" value="Connexion" /&gt;
        &lt;/fieldset&gt;
    &lt;/form&gt;
 &lt;/body&gt;
 &lt;/html&gt;
</programlisting>		
			</section>
			<section>
				<title>identification.js, et la magie opère</title>
			 	<para>Le fichier identification.js contient <emphasis role="strong">tout</emphasis> le code Javascript permettant de rendre la page d'identification interactive. On y trouve les fonctions pour la création d'une connection avec XMLHttpRequest, la lecture du formulaire et l'affichage du résultat, le tout sans recharger la page.</para>
<programlisting>
window.onload = function()
 {
    //on associe la fonction verifId à
    //l'événénement onsubmit du formulaire
    document.getElementById('frmIdentification').onsubmit = verifId;
 }
</programlisting>
				<para>La première étape est l'assignation d'une fonction à une comportement du formulaire. Ici, la fonction <token>verifId</token> sera déclenchée lorsque le formulaire est envoyé. Cette fonction doit donc être déclarée. On peut le faire avec le code suivant :</para>
<programlisting>
function verifId()
 {
    //envoi des données
    return !sendData(
       'GET',
       'identification-xml.php',
       'xmlhttp=1&amp;'+
       'login='+document.getElementById('txtLogin').value+
       '&amp;'+
       'password='+document.getElementById('txtPassword').value);
 }
</programlisting>
			<para>Il faut noter que cette fonction renvoie la valeur <token>false</token> lorsque l'envoi s'est bien passé pour éviter que le formulaire ne soit envoyé par la voie classique (et inversement renvoie <token>true</token> lorsqu'il faut envoyer le formulaire par la voie classique).</para>
			<para>Deux autres fonctions sont également définies, une pour la création d'un objet XMLHttpRequest (vue plus tôt) et une autre pour faciliter l'envoi de données. Cette dernière se contente de formater les données correctement et d'utiliser l'objet XMLHttpRequest pour communiquer de manière asynchrone avec le serveur.</para>
<programlisting>
/**
  * Envoie des données à l'aide d'XmlHttpRequest?
  * @param string methode d'envoi ['GET'|'POST']
  * @param string url
  * @param string données à envoyer sous la forme var1=value1&amp;var2=value2...
  */
 function sendData(method, url, data)
 {
    var xmlhttp = getHTTPObject();

    if (!xmlhttp)
    {
        return false;
    }

    if(method == "GET")
     {
     if(data == 'null')
     {
            xmlhttp.open("GET", url, true); //ouverture asynchrone
     }
     else
     {
            xmlhttp.open("GET", url+"?"+data, true);
     }
        xmlhttp.send(null);
     }
     else if(method == "POST")
     {
        xmlhttp.open("POST", url, true); //ouverture asynchrone
        xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
     xmlhttp.send(data);
     }
    return true;
 }
</programlisting>
			</section>
			<section>
				<title>lib.identification.php</title>
			 <para>Ce script <acronym>PHP</acronym> se contente de fournir les fonctions permettant l'identification d'un utilisateur. Dans cet exemple, seule une comparaison sur les chaînes de caractères est faite. Il faut noter que cet exemple simplifié pour les besoins de l'explication n'est absolument pas sécurisé.</para>
<programlisting>
&lt;?php

 function identification($login, $password)
 {
    if (($login == 'login')&amp;&amp;($password == 'password'))
    {
        //l'utilisateur est reconnu
        //procéder à l'identification
        return 'Vous êtes identifié';
    }
    else
    {
        //l'utilisateur n'est pas reconnu
        return 'Mauvais login ou mot de passe';
    }
 }

 ?&gt;
</programlisting>			
			</section>
			<section>
				<title>identification-xml.php</title>
			 <para>Ce script <acronym>PHP</acronym> est celui qui va dialoguer avec XMLHttpRequest en recueillant les informations, appliquant la fonction d'identification fournie par lib. identification.php et en renvoyant le résultat. Ce résultat est minimal, car seules les informations nécessaires sont envoyées.</para>
<programlisting>
&lt;?php
 include dirname(FILE).'/lib.identification.php';

 if ((!empty($_GET['login']))&amp;&amp;(!empty($_GET['password'])))
 {
    $resultat = identification($_GET['login'], $_GET['password']);
 }
 else
 {
    $resultat = 'erreur';
 }

 echo $resultat;
 ?&gt;
</programlisting>		
			</section>
			<section>
				<title>identification.php</title>
			 <para>Ce script fait partie de la voie de secours prévue en cas de problèmes avec Javascript. C'est le genre de script qu'on retrouve habituellement dans les applications web: il récupère les informations du formulaire, les traite et affiche une page de résultat.</para>				
<programlisting>
&lt;?php
 include dirname(FILE).'/lib.identification.php';

 if ((!empty($_GET['login']))&amp;&amp;(!empty($_GET['password'])))
 {
    $resultat = identification($_GET['login'], $_GET['password']);
 }
 else
 {
    $resultat = 'erreur';
 }
 ?&gt;
 &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
 &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"&gt;
 &lt;head&gt;
    &lt;meta http-equiv="Content-Type" content="text/HTML; charset=iso-8859-1" /&gt;
    &lt;meta http-equiv="Content-Language" content="fr" /&gt;

    &lt;title&gt;Identification avec XmlHttpRequest?&lt;/title&gt;
 &lt;/head&gt;

 &lt;body&gt;
    &lt;p&gt;&lt;?php echo $resultat ?&gt;&lt;/p&gt;
 &lt;/body&gt;
 &lt;/html&gt;
</programlisting>
			</section>
		</section>
	</section>
	<section>
		<title>Conclusion</title>
		<para>Même si cette technologie semble pouvoir révolutionner les pratiques, il faut néanmoins l'utiliser avec précautions. Des solutions de repli doivent être prévues pour les personnes ne disposant pas de Javascript. Il est également important de coller au comportement habituel des navigateurs et de ne pas négliger les bonnes pratiques généralement admises.</para>
		<para>Pour aller plus loin :</para>
		<itemizedlist>
    	<listitem>
      	<para><ulink url="http://www.w3.org/Protocols/rfc2616/rfc2616.html"><acronym>RFC</acronym> 2616 sur <acronym>HTTP</acronym> 1.1</ulink> ;</para>
    	</listitem>
    	<listitem>
      	<para><ulink url="http://jpspan.sourceforge.net/">La bibliothèque <acronym>JPSPAN</acronym> pour de l'invocation de classes distantes</ulink>.</para>
    	</listitem>
  	</itemizedlist>
	</section>
</article>