L’objet XMLHttpRequest

Openweb.eu.org > Articles  > L’objet XMLHttpRequest

Abstract

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.

Article

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, cette technologie n'est pas un standard du W3C , lequel propose des fonctionnalités similaires à travers la recommandation Document Object Model (DOM) Level 3 Load and Save Specification.

Cet objet permet de faire des requêtes HTTP afin de récupérer des données au format XML 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.

Les avantages possibles :

  • Diminution de la bande passante : seules les données sont chargées et non plus tout le document ;
  • Interactivité accrue : plus de rechargement de la page ;
  • 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).

Les inconvénients possibles :

  • Ne fonctionne pas sans Javascript, ni dans les navigateurs les plus anciens ;
  • Ne fonctionne qu'avec HTTP : il est impossible de récupérer des données sur un disque local (ce qui est normal) ;
  • Les requêtes en dehors du domaine provoquent un avertissement de sécurité ;
  • Peut empêcher des comportements habituels du navigateur :

    • Marques-pages et liens vers la page ;
    • Enregistrement des pages ;
    • Bouton retour.

Une architecture client-serveur

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 XML à travers HTTP 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 :

  • L'objet XMLHttpRequest est créé. Un gestionnaire de réponse lui est associé.
  • Il est alors utilisé pour créer et effectuer une requête HTTP.
  • 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.

Note à propos d'AJAX

L'utilisation de XMLHttpRequest fait immédiatement penser à AJAX (Asynchronous JAvascript XML). Cette architecture client/serveur consiste en effet à découper une application web de la façon suivante :

  • une présentation utilisant XHTML et CSS ;
  • la manipulation dynamique des pages à travers DOM ;
  • la manipulation des données avec XML et XSLT ;
  • l'échange des données de manière asynchrone avec XMLHttpRequest ;
  • le tout étant assemblé avec du Javascript.

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 XML. 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.

De la théorie à la pratique

Côté client, l'objet Javascript XMLHttpRequest

L'objet n'étant pas standardisé, son implémentation varie légèrement selon les navigateurs. Alors que Microsoft dispose des fonctions ActiveXObject("Msxml2.XMLHTTP") et ActiveXObject("Microsoft.XMLHTTP"), selon le moteur XML utilisé, les autres navigateurs utilisent simplement la fonction XMLHttpRequest().

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 XMLHttpRequest ou la valeur false 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.

function getHTTPObject()
{
  var xmlhttp = false;

  /* Compilation conditionnelle d'IE */
  /*@cc_on
  @if (@_jscript_version >= 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 && 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;
}

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.

Utiliser cet objet : propriétés et méthodes

Une fois créé, l'objet peut être manipulé à travers ses propriétés et méthodes :

Les propriétés de l'objet XMLHttpRequest
Propriété Description
onreadystatechange 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.
readyState statut de l'objet.
responseText Réponse sous forme de chaîne de caractères.
responseXML Réponse sous forme d'objet DOM.
status code numérique de réponse du serveur HTTP
statusText message accompagnant le code de réponse.

Les code possibles pour le statut de l'objet sont :

  • 0 = non initialisé ;
  • 1 = ouverture. La méthode open() a été appelée avec succès ;
  • 2 = envoyé. La méthode send() a été appelée avec succès ;
  • 3 = en train de recevoir. Des données sont en train d'être transférées, mais le transfert n'est pas terminé ;
  • 4 = terminé. Les données sont chargées.
Les méthodes de l'objet XMLHttpRequest et leurs paramètres
Méthode Paramètres Description
abort () Abandonne la requête.
getAllResponseHeaders () Renvoie l'ensemble de l'entête de la réponse sous forme de chaîne de caractères.
getResponseHeader ("champEntete") Renvoie la valeur d'un champ d'entête HTTP.
open ("method", "URL"[, asyncFlag[, "userName"[, "password"]]]) Prépare une requête en indiquant la méthode, l'URL, la drapeau de synchronisation, le nom d'utilisateur et le mot de passe.
send (contenu) Effectue la requête, éventuellement en envoyant les données.
setRequestHeader ("champ", "valeur") Assigne une valeur à un champ d'entête HTTP qui sera envoyé lors de la requête.

Faire une requête

On considère qu'un gestionnaire d'événement a été assigné à la propriété onreadystatechange. Voici quelques exemples de requêtes courantes avec les méthodes HEAD, GET et POST :

Une requête de type HEAD
/* 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);
Une requête de type GET

/* 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&var2=valeur2",true); 
/* Effectue la requête : */
xmlhttp.send(null); 
Une requête de type POST
/* 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&var2=valeur2");

Côté serveur

Côté serveur, le programmeur est libre. Quels que soient le langage utilisé (PHP, ASP, Java, etc.) et les traitements effectués, il suffit de ne renvoyer que les informations nécessaires sous forme de flux XML.

Exemple concret, identification à travers XMLHttpRequest

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.

Structure générale de l'application

La structure d'une application utilisant XMLHttpRequest doit prendre en compte qu'il n'est pas toujours possible de l'utiliser et donc prévoir une solution de repli.

Dans notre exemple, il y a deux moyens de faire passer les informations d'identification :

  • 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)
  • à travers XMLHttpRequest qui envoie les données et reçoit la réponse du serveur (à droite sur le schéma)

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.).

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).

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.

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.

Plongée dans le code

identification.html, c'est par là que tout commence

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.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">

 <head>
    <meta http-equiv="Content-Type" content="text/HTML; charset=iso-8859-15" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <meta http-equiv="Content-Language" content="fr" />

    <title>Identification avec XmlHttpRequest?</title>

    <script type="text/javascript" src="identification.js"></script>
 </head>

 <body>
    <form action="identification.php" method="get" id="frmIdentification">
        <fieldset>

            <legend>Connexion</legend>

            <label for="txtLogin">Login</label>
            <input type="text" value="" name="login" id="txtLogin" />

            <label for="txtPassword">Mot de passe</label>

            <input type="text" value="" name="password" id="txtPassword" />

            <input type="submit" value="Connexion" />
        </fieldset>
    </form>
 </body>
 </html>

identification.js, et la magie opère

Le fichier identification.js contient tout 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.

window.onload = function()
 {
    //on associe la fonction verifId à
    //l'événénement onsubmit du formulaire
    document.getElementById('frmIdentification').onsubmit = verifId;
 }

La première étape est l'assignation d'une fonction à une comportement du formulaire. Ici, la fonction verifId 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 :

function verifId()
 {
    //envoi des données
    return !sendData(
       'GET',
       'identification-xml.php',
       'xmlhttp=1&'+
       'login='+document.getElementById('txtLogin').value+
       '&'+
       'password='+document.getElementById('txtPassword').value);
 }

Il faut noter que cette fonction renvoie la valeur false lorsque l'envoi s'est bien passé pour éviter que le formulaire ne soit envoyé par la voie classique (et inversement renvoie true lorsqu'il faut envoyer le formulaire par la voie classique).

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.

/**
  * 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&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;
 }
lib.identification.php

Ce script PHP 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é.

<?php

 function identification($login, $password)
 {
    if (($login == 'login')&&($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';
    }
 }

 ?>

identification-xml.php

Ce script PHP 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.

<?php
 include dirname(FILE).'/lib.identification.php';

 if ((!empty($_GET['login']))&&(!empty($_GET['password'])))
 {
    $resultat = identification($_GET['login'], $_GET['password']);
 }
 else
 {
    $resultat = 'erreur';
 }

 echo $resultat;
 ?>
identification.php

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.

<?php
 include dirname(FILE).'/lib.identification.php';

 if ((!empty($_GET['login']))&&(!empty($_GET['password'])))
 {
    $resultat = identification($_GET['login'], $_GET['password']);
 }
 else
 {
    $resultat = 'erreur';
 }
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
 <head>

    <meta http-equiv="Content-Type" content="text/HTML; charset=iso-8859-1" />
    <meta http-equiv="Content-Language" content="fr" />

    <title>Identification avec XmlHttpRequest?</title>
 </head>

 <body>

    <p><?php echo $resultat ?></p>
 </body>
 </html>

Conclusion

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.

Pour aller plus loin :

À propos de cet article

  • Openweb.eu.org
  • Profil : Expert, Gourou
  • Technologie : DOM
  • Thème : Pages dynamiques
  • Auteur :
  • Publié le :
  • Mise à jour : 26 juin 2008
  • 7 commentaires

Vos commentaires

  • ddpetit Le 21 septembre 2010 à 10:24

    Merci pour votre article très complet. Grâce à lui j’utilise désormais l’objet XMLHttpRequest sur mon site dédié au mandataire auto, ce qui me permet de faire une recherche asynchrone.

  • Le 10 janvier 2011 à 09:07

    Bonjour et merci pour cet article. J’ai tenté de mettre en place sur la préprod de mon site choisir sa voiture neuve, je me retrouve avec une erreur 403, forbidden... Pas normal ça ?

  • XiXiMe Le 4 avril 2011 à 21:35

    Bonjour,

    Merci pour cet article.

    Malgré tout il ne manquerai pas quelques détails importants ? :)

    Comment récupère t-on le contenu de la requête POST de l’objet XMLHttpRequest dans la page PHP ?

    Que contient data dans le cas d’un requête POST ?

    Merci beaucoup.

    Cordialement,

  • Dqni Le 14 mai 2011 à 22:34

    Bonjour,
    Actuellement je fais une requête xhr pour envoyer une page php dynamiquement par innerhtml dans une div, jusque là tout se passe bien. mais mes scripts (genre mootools et lightbox) qui sont appelés dans le

    de cette page php ne sont pas lancés.. alors que quand je lance la page php les scripts fonctionnent... Comment arranger ce probléme ? voici ma requete xhr :

    var xhr = getXhr()
    xhr.onreadystatechange = function()

    if(xhr.readyState == 4 && xhr.status == 200)

    resultat =(xhr.responseText) ;


    xhr.open("POST","page.php",true) ;
    xhr.send(null) ;

    et mon inner html :

    $(’div1’).innerHTML=resultat ;

    Merci pour votre aide

  • Tib Le 29 août 2012 à 22:20

    Merci pour cet article. :)

  • Philippe Le 25 juin 2014 à 16:19

    Pourquoi ne pas faire un article sur la spécification "Document Object Model (DOM) Level 3 Load and Save Specification", ça manque cruellement sur le net, une spécification n’est pas fait pour expliquer aux programmeurs, mais bien à ceux qui implémente les spécifications dans leurs navigateurs, c’est donc difficile à comprendre à partir de la spécification, une explication plus pédagogique serait très utile.

  • giay decal in ma vach Le 1er février 2016 à 09:04

    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.

Vos commentaires

modération a priori

Attention, votre message n’apparaîtra qu’après avoir été relu et approuvé.

Qui êtes-vous ?
Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Suivre les commentaires : RSS 2.0 | Atom