Premiers pas

 

Cet article vous guide à travers les bases d'AJAX et vous donne deux exemples clefs-en-main pour débuter.

Présentation d'Ajax

Ajax est un raccourci pour Asynchronous JavaScript + XML (JavaScript  asynchrone plus XML) inventé par Jesse James Garrett. Pour simplifier, il s'agit d'employer l'objet non standard XMLHttpRequest pour communiquer avec des scripts situés sur le serveur. L'objet permet d'échanger des informations sous différents formats (dont XML, HTML ou texte), mais son principal attrait est sa nature « asynchrone » : tout cela peut se faire sans recharger la page. C'est ce qui permet de mettre à jour certaines parties d'une page sur base d'évènements déclenchés par l'utilisateur.

Les deux fonctionnalités combinées sont les possibilités de :

  • faire des requêtes vers le serveur sans avoir à recharger la page ;
  • analyser et travailler avec des documents XML.

Étape 1 — Lancement d'une requête HTTP

Pour faire une requête HTTP vers le serveur à l'aide de JavaScript, il faut disposer d'une instance d'une classe fournissant cette fonctionnalité. Une telle classe a d'abord été introduite dans Internet Explorer sous la forme d'un objet ActiveX appelé XMLHTTP. Par la suite, Mozilla, Safari et d'autres navigateurs ont suivi en implémentant une classe XMLHttpRequest qui fournit les mêmes méthodes et propriétés que l'objet ActiveX original de Microsoft.

Par conséquent, pour créer une instance (un objet) de la classe désirée fonctionnant sur plusieurs navigateurs, vous pouvez utiliser :

if (window.XMLHttpRequest) { // Mozilla, Safari, ...
    httpRequest = new XMLHttpRequest();
}
else if (window.ActiveXObject) { // IE
    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}

(Pour illustrer le principe, le code ci-dessus est une version un peu simplifiée de celui qui est utilisé pour créer une instance XMLHTTP. Pour un exemple plus réaliste, voir la troisième étape de cet article.)

Certaines versions de certains navigateurs Mozilla ne fonctionneront pas correctement si la réponse du serveur n'a pas un en-tête XML mime-type. Pour vous en assurer, vous pouvez utiliser un appel de fonction supplémentaire pour écraser l'en-tête envoyé par le serveur, juste au cas où il ne s'agit pas de text/xml.

httpRequest = new XMLHttpRequest();
httpRequest.overrideMimeType('text/xml');

La chose suivante à faire est de décider ce que vous ferez après avoir reçu la réponse du serveur. À ce stade, vous devez juste communiquer à l'objet de requête HTTP le nom de la fonction JavaScript qui effectuera le travail d'analyse de la réponse. Pour cela, assignez à la propriété onreadystatechange de l'objet le nom de la fonction JavaScript que vous envisagez d'utiliser, comme ceci :

httpRequest.onreadystatechange = nomDeLaFonction;

Notez qu'il n'y a ni parenthèses après le nom de la fonction, ni paramètres fournis, car vous ne faites qu'assigner une référence à la fonction sans l'appeler effectivement. Par ailleurs, au lieu de donner un nom de fonction, vous pouvez utiliser la technique JavaScript de définition de fonctions au vol (ce qu'on appelle une fonction anonyme), et définir à cet endroit les actions à effectuer sur la réponse, comme ceci :

httpRequest.onreadystatechange = function() {
    // instructions de traitement de la réponse
};

Ensuite, après avoir déclaré ce qui se produit lorsque la réponse est reçue, il s'agit de lancer effectivement la requête. Il faut pour cela appeler les méthodes open() et send() de la classe de requête HTTP, comme ceci :

httpRequest.open('GET', 'http://www.example.org/some.file', true);
httpRequest.send();
  • Le premier paramètre de l'appel à open() est la méthode de requête HTTP — GET, POST, HEAD ou toute autre méthode que vous voulez utiliser et est gérée par le serveur. Laissez le nom de la méthode en majuscules comme spécifié par la norme HTTP ; autrement certains navigateurs (comme Firefox) peuvent ne pas traiter la requête. Pour plus d'informations sur les méthodes de requêtes HTTP possibles, vous pouvez consulter les spécifications du W3C
  • Le second paramètre est l'URL de la page que vous demandez. Pour des raisons de sécurité, il n'est pas possible d'appeler des pages se situant sur un autre domaine. Veillez à utiliser le nom de domaine exact sur toutes vos pages ou vous obtiendrez une erreur « permission refusée » à l'appel d'open(). Une erreur courante est de charger le site via domaine.tld, mais d'essayer d'appeler des pages avec www.domain.tld.
  • Le troisième paramètre précise si la requête est asynchrone. Si mis à TRUE, l'exécution de la fonction JavaScript se poursuivra en attendant l'arrivée de la réponse du serveur. C'est le A d'AJAX.

Le paramètre de la méthode send() peut être n'importe quelle donnée que vous voulez envoyer au serveur en cas d'utilisation de la méthode POST. Les données doivent être sous la forme d'une chaîne de requête, comme :

nom=valeur&autrenom=autrevaleur&ainsi=desuite

Notez que si vous voulez envoyer des données avec la méthode POST, vous devrez changer le type MIME de la requête à l'aide de la ligne suivante :

httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

Autrement, le serveur ignorera les données envoyées.

Étape 2 — Gestion de la réponse du serveur

Lors de l'envoi de la requête, vous avez désigné une fonction JavaScript pour traiter la réponse.

httpRequest.onreadystatechange = nomDeLaFonction;

Voyons maintenant ce que cette fonction doit faire. Tout d'abord, elle doit vérifier l'état de la requête. Si cet état a une valeur de 4, cela signifie que la réponse du serveur a été reçue dans son intégralité et qu'elle peut maintenant être traitée.

if (httpRequest.readyState == 4) {
    // tout va bien, la réponse a été reçue
} else {
    // pas encore prête
}

Voici la liste complète des valeurs de readyState :

  • 0 (non initialisée)
  • 1 (en cours de chargement)
  • 2 (chargée)
  • 3 (en cours d'interaction)
  • 4 (terminée)

(Source)

La seconde vérification concerne le code d'état de la réponse HTTP du serveur. Tous les codes possibles sont listés sur le site du W3C. Dans notre cas, nous sommes seulement intéressés par la réponse 200 OK.

if (httpRequest.status == 200) {
    // parfait !
} else {
    // il y a eu un problème avec la requête,
    // par exemple la réponse peut être un code 404 (Non trouvée) 
    // ou 500 (Erreur interne au serveur)
}

Après avoir vérifié l'état de la requête et le code d'état HTTP de la réponse, vous pouvez traiter à votre guise les données envoyées par le serveur. Il existe deux manières d'accéder à ces données :

  • httpRequest.responseText — renvoie la réponse du serveur sous la forme d'une chaîne de texte
  • httpRequest.responseXML — renvoie la réponse sous la forme d'un objet XMLDocument que vous pouvez parcourir à l'aide des fonctions DOM de JavaScript

Étape 3 — Un exemple simple

Rassemblons tous ces éléments dans un exemple : une requête HTTP simple. Notre JavaScript demande un document HTML, test.html, qui contient le texte « Je suis un test. », et nous affichons le contenu de ce fichier test.html dans un message alert().

<script type="text/javascript" language="javascript">

    function makeRequest(url) {

        var httpRequest = false;

        if (window.XMLHttpRequest) { // Mozilla, Safari,...
            httpRequest = new XMLHttpRequest();
            if (httpRequest.overrideMimeType) {
                httpRequest.overrideMimeType('text/xml');
                // Voir la note ci-dessous à propos de cette ligne
            }
        }
        else if (window.ActiveXObject) { // IE
            try {
                httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch (e) {
                try {
                    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch (e) {}
            }
        }

        if (!httpRequest) {
            alert('Abandon :( Impossible de créer une instance XMLHTTP');
            return false;
        }
        httpRequest.onreadystatechange = function() { alertContents(httpRequest); };
        httpRequest.open('GET', url, true);
        httpRequest.send(null);

    }

    function alertContents(httpRequest) {

        if (httpRequest.readyState == 4) {
            if (httpRequest.status == 200) {
                alert(httpRequest.responseText);
            } else {
                alert('Un problème est survenu avec la requête.');
            }
        }

    }
</script>
<span
    style="cursor: pointer; text-decoration: underline"
    onclick="makeRequest('test.html')">
        Effectuer une requête
</span>

Dans cet exemple :

  • L'utilisateur clique sur le lien « Effectuer une requête » dans le navigateur ;
  • Ceci appelle la fonction makeRequest() avec un paramètre – le nom test.html d'un fichier HTML situé dans le même répertoire ;
  • la requête est faite et ensuite (onreadystatechange) l'exécution est passée à alertContents();
  • alertContents() vérifie si la réponse a été reçue et est correcte, et affiche ensuite la contenu du fichier test.html dans un message alert().

Vous pouvez tester l'exemple ici et consulter le fichier de test.

Note : La ligne httpRequest.overrideMimeType('text/xml'); ci-dessus provoquera des erreurs dans la console JavaScript de Firefox 1.5 ou supérieur (comme documenté dans le bug 311724) si la page appelée par XMLHttpRequest n'est pas du XML valide (par exemple s'il s'agit de texte simple). Ce comportement est en réalité le comportement correct et cet article sera revu ultérieurement.

Note 2 : Si vous envoyez une requête vers un bout de code dynamique qui renvoie du XML, plutôt que vers un fichier XML statique, vous devez définir certains en-têtes de réponse pour que votre page fonctionne non seulement avec Mozilla, mais aussi avec Internet Explorer. Si vous ne spécifiez pas l'en-tête Content-Type: application/xml, IE produira une erreur JavaScript « Objet attendu » après la ligne à laquelle vous tenterez d'accéder à un élément XML. Si vous ne spécifiez pas l'en-tête Cache-Control: no-cache, le navigateur mettra la réponse en cache et n'effectuera plus jamais la requête ultérieurement, ce qui peut faire du débogage un véritable défi.

Note 3 : Si la variable httpRequest est utilisée globalement, des appels concurrents à makeRequest() peuvent s'écraser l'un l'autre, provoquant un effet de race condition. On peut s'en prémunir en rendant la variable httpRequest locale à la fonction et en la passant en paramètre à la fonction alertContent().

Note 4 : Pour procéder à l'enregistrement de la fonction de callback onreadystatechange, aucun paramètre n'est permis. C'est pourquoi le code suivant ne fonctionnera pas :

httpRequest.onreadystatechange = alertContents(httpRequest); // (ne fonctionne pas)

Pour enregistrer la fonction correctement, vous pouvez soit passer les paramètres indirectement via la fonction anonyme, ou utiliser httpRequest comme une variable globale. Voici quelques exemples :

httpRequest.onreadystatechange = function() { alertContents(httpRequest); }; //1 (requêtes simultanées)
httpRequest.onreadystatechange = alertContents; //2 (variable globale)

La méthode 1 permet d'avoir plusieurs requêtes lancées simultanément, la méthode 2 est utilisée si httpRequest est une variable globale.

Note 5 : Si erreur de communication se produit (par exemple le serveur web qui cesse de répondre), une exception se déclenchera dans la méthode onreadystatechange lors de l'accès à la variable .status. Assurez-vous d'envelopper votre bloc if...then dans un try...catch. (cf bug 238559).

function alertContents(httpRequest) {

        try {
            if (httpRequest.readyState == 4) {
                if (httpRequest.status == 200) {
                    alert(httpRequest.responseText);
                } else {
                    alert('Un problème est survenu au cours de la requête.');
                }
            }
        }
        catch( e ) {
            alert("Une exception s'est produite : " + e.description);
        }

    }

Étape 4 — Travailler avec des réponses XML

Dans l'exemple précédent, après la réception de la réponse à la requête HTTP, nous avons utilisé la propriété responseText de l'objet de requête, qui contient le contenu du fichier test.html. Essayons maintenant la propriété responseXML.

Tout d'abord, créons un document XML valide qui sera l'objet de la requête. Le document (test.xml) contient ce qui suit :

<?xml version="1.0" ?>
<root>
    Je suis un test.
</root>

Dans le script, il est juste nécessaire de remplacer la ligne de requête par :

...
onclick="makeRequest('test.xml')">
...

Ensuite, dans alertContents(), il faut remplacer la ligne alert(httpRequest.responseText); par :

var xmldoc = httpRequest.responseXML;
var root_node = xmldoc.getElementsByTagName('root').item(0);
alert(root_node.firstChild.data);

De cette façon, nous avons pris l'objet XMLDocument donné par responseXML et nous avons utilisé des méthodes DOM pour accéder à certaines données contenues dans le document XML. Vous pouvez consulter le fichier test.xml et le script mis à jour.

Pour plus d'information sur les méthodes DOM, consultez les documents sur l'implémentation de DOM dans Mozilla.

Catégories

Interwiki

Étiquettes et contributeurs liés au document

Étiquettes :
Contributeurs ayant participé à cette page : Fredchat, Taken, arena, Rbories, Cbi1net, Rodolphe, VincentN, Oumar, Chbok, Diskostu, BenoitL, Mgjbot, P_MO
Dernière mise à jour par : P_MO,