AJAX

De EduTech Wiki
Aller à la navigation Aller à la recherche

Cet article est en construction: un auteur est en train de le modifier.

En principe, le ou les auteurs en question devraient bientôt présenter une meilleure version.



Initiation à la pensée computationnelle avec JavaScript
Module: JavaScript dans le navigateur ◀▬ ▬▶
◀▬▬▶
à finaliser avancé
2018/06/16
Catégorie: JavaScript


Introduction

AJAX est un acronyme signifiant Asynchronous JavaScript and XML et qui designe un ensemble de technologies pour créer des pages web dynamiques et qui peuvent communiquer avec un serveur. AJAX est donc une technologie utilisée pour créer des rich internet applications (RIA). La plupart des applications web 2.0 utilisent la technologie AJAX.

L'acronyme a été maintenu en dépit du fait que :

  • Les requêtes ne doivent pas être forcément asynchrones
  • JavaScript n'est pas la seule manière pour faire ce type de requêtes (mais sans doute la plus fréquente)
  • Le format d'échange ne se limite pas à XML, on peut utiliser par exemple du JSON (très fréquent), du HTML, ou même des simples fichiers de texte. Dans des cas plus rares, on peut récupérer également des fichiers plus lourds comme des images ou des streams audio/vidéo.

Pour cette raison, on se réfère de plus en plus à AJAX comme l'une des Web API (voir la page JavaScript pour la liste) qui permet de récupérer de l'information depuis un serveur, mais l'utilisation de l'acronyme est encore très répandue.

Description et intérêt

Fonctionnement général d'AJAX : les requêtes sont envoyées après que la page a été téléchargée une première fois dans le navigateur de l'utilisateur.

Par rapport à une application web "traditionnelle" (avec des formulaires et un bouton "submit"), AJAX permet de créer des applications qui ont des interfaces plus riches et qui permettent d'échanger des données avec un serveur sans recharger la page. Cela signifie qu'on peut, par exemple, incorporer progressivement des informations qui sont récupérées sur une autre page, se trouvant même sur un autre site si celui-ci le permet (voir Cross-Origin Ressource Sharing, ou CORS plus bas dans la page).

Originairement, AJAX a été conçu pour donner une expérience plus proche des applications desktop, notamment en ce qui concerne la transition entre états de l'application. Un site web "traditionnel" se compose d'un état différent pour chaque page et pour passer d'un état à l'autre il est nécessaire de cliquer sur un lien qui pointe vers une autre page, et par conséquent enchaîner le mécanisme de réponse/requête à la base du protocole HTTP.

Avec AJAX, il est possible d'envoyer une nouvelle requête HTTP en arrière plan, c'est-à-dire que la requête est envoyée par la page même sur laquelle vous vous trouvez. Le mécanisme peut être décrit de la manière suivante (voir image) :

  1. Première requête "normale"
    Le navigateur pointe une première fois sur une page à une adresse donnée, cette page est renvoyé en réponse par le serveur qui la héberge. Cette page contient un ou plusieurs script JavaScript qui permettent d'envoyer des nouvelles requêtes sans mettre à jour la page.
  2. Deuxième requête AJAX
    Le manière décalée, à tout moment et suite à n'importe quel événement, une nouvelle requête AJAX peut être envoyé, dans ce cas au même serveur qui héberge la page principale. Il faudra bien entendu envoyer la requête à une autre page (i.e. à un autre URL du même domaine). Il s'agit souvent d'une page web dynamique, par exemple connectée à une base de données, qui récupère de l'information qui est censée changer dans le temps.
  3. Troisième requête AJAX
    La même page peut envoyer autant de requêtes qu'elles veut, sur le même serveur ou sur autres. Dans ce cas, il faut que le serveur accepte des requêtes de type AJAX qui vient d'une autre origine (i.e. un autre domaine)

Les requêtes AJAX peuvent se répéter dans le temps, sur le même URL ou sur un autre. Dans tous le cas, le code qui permet de mener à bien une requête asynchrone s'occupe de :

  • Identifier la page qui contient les informations d'intérêt (i.e. son URL)
  • Envoyer une requête qui peut :
    • Demander tout simplement des informations sans en envoyer
    • Envoyer des informations sans en demander, par exemple à travers un formulaire, mais également de manière "cachée" comme dans les systèmes de tracking de l'activité
    • Envoyer et demander des informations en même temps (e.g. spécifier des informations pour obtenir une réponse spécifique)
  • Recevoir une confirmation sur le résultat de la transaction, par exemple si la page n'a pas été trouvée, il manque l'authorization pour pouvoir accéder à la ressource, ou encore le serveur n'accepte pas de requêtes AJAX.
  • Incorporer les éventuelles informations reçues en réponse dans la page

Limitation : Cross-Origin Ressource Sharing

Les requêtes AJAX sont gérées directement depuis le navigateur de l'utilisateur et donc c'est comme si l'utilisateur en faisait demande, même si en réalité c'est un script qui décide quelle page pointer pour récupérer de l'information. Ceci pose un problème "éthique" à la fois du côté de l'utilisateur et des développeurs/administrateurs.

  • Au niveau utilisateur, la personne ne connait pas les URL sous-jacents qu'elle va visiter en arrière-plan.
  • Au niveau développeurs/administrateurs, des ressources appartenant à un site peuvent être demandées par des utilisateurs mais à travers un autre site, donc au final l'utilisateur ne pourrait même pas savoir que l'information appartient au site Y et non pas au site X qu'il est en train de visiter. De plus, des concurrents du site Y pourraient envoyer une grande quantité de requêtes AJAX à travers les navigateurs/ordinateurs des utilisateurs pour le ralentir, ce qui serait plus difficile à bloquer par rapport à un attaque qui vient d'un serveur et qui serait donc plus simple à isoler.

Pour limiter les problèmes soulevés par ces aspects, il y a moyen technique de détecter si une requête est envoyée de manière "traditionnelle", donc si c'est l'utilisateur qui décide de pointer volontairement vers l'URL X (en écrivant l'adresse dans la barre de son navigateur ou à travers un lien hypertextuel), ou si ce fait à travers AJAX.

Ce type d'information permet notamment aux développeurs/administrateurs de décider si accepter ce qu'on appelle le Cross-Origin Ressource Sharing (ou CORS), c'est-à-dire des requêtes qui arrivent d'un navigateur (ou plus généralement un agent), mais de manière détournée à travers un autre site qui ne partage pas la même origine. Les règles pour déterminer si l'origine de la requête est la même peuvent varier, par exemple on peut considérer deux origines différentes :

  • Une requête qui arrive sur la page edutechwiki.unige.ch depuis un site www.interested-in-your-page.com (domaines différents)
  • Mais également une requête qui arrive sur la page edutechwiki.unige.ch depuis le site tecfa.unige.ch (sous-domaines différents)

Passer par intermédiaire d'une requête server-to-server

La décision d'accepter ou moins des requêtes d'autres origines (et éventuellement quelles origines) est une décision des administrateurs du serveur auquel sont envoyées les requêtes. Souvent même des serveurs/services qui sont disponibles à partager des ressources n'acceptent cependant pas que ce soit fait à travers AJAX, mais imposent que la requête viennent d'un serveur, par exemple à travers une page dynamique côté-serveur (voir comment le faire par exemple avec Node.js). Dans ce cas, on peut toujours bénéficier des requêtes AJAX, mais il faudra faire un détour :

  1. La page qui a dans son script côté-client des requêtes AJAX pour des ressources qui se trouvent sur une autre origine doit d'abord..
  2. faire une requête à une page dynamique qui se trouve sur le même serveur...
  3. Cette page s'occupe à son tour d'envoyer une requête server-to-server et de gérer la réponse
  4. La réponse est transmise à la page qui a originairement envoyée la requête AJAX

Cette méthode garanti également plus de sécurité et de contrôle sur l'information qui au final est envoyée à l'utilisateur.

Fonctionnement technique

Il existe différentes manières d'incorporer des requêtes AJAX dans son propre code. Dans le passé, on pouvait faire ce type d'échange également avec Flash, mais depuis sa presque totale disparition (au moins en tant que plugin pour le navigateur), ce rôle est désormais limité à JavaScript.

Il existe en principe trois manières pour faire du AJAX avec JavaScript :

  1. La méthode originale, mais ancienne, qui utilise l'objet XMLHttpRequest()
  2. La méthode, plus moderne, qui utilise l'API fetch disponible dans les navigateurs les plus récents.
  3. Utiliser des Bibliothèques JavaScript qui exploite l'une, l'autre ou les deux méthodes en même temps pour garantir la compatibilité, mais à travers du codage facilité/optimisé.

XMLHttpRequest()

Le fonctionnement de XMLHttpRequest est plutôt complexe, c'est pourquoi il existe des bibliothèques qui essaient de rendre le mécanisme des requêtes asynchrones plus aisé. De manière schématique, une requête AJAX avec vanilla JavaScript nécessite de :

  • Une fonction qui détermine quoi faire une fois que la réponse est obtenue
  • La déclaration de la requête à faire, notamment si on veut :
    • GET : juste récupérer des informations
    • POST : envoyer des informations (e.g. à travers un formulaire)
    • Autres possibilités : DELETE, PUT, PATCH, etc. (voir RESTful API pour plus d'info)
  • L'envoie de la requête

Voici un exemple qui demande de l'information à l'API de ce Wiki pour chercher le contenu de la page JavaScript. Vous pouvez voir le contenu de cette page sous cette adresse : http://edutechwiki.unige.ch/fmediawiki/api.php?action=parse&page=JavaScript&format=json (veuillez noter comme on demande du JSON à travers l'attribut format=json à la fin de l'URL).

//Créer une instance de l'objet var XMLHttpRequest;
var asynchRequest = new XMLHttpRequest();

//Créer la fonction qui détermine quoi faire une fois la réponse obtenue
asynchRequest.onreadystatechange = function () {
    //Contrôler que tout a bien marché
    if (asynchRequest.readyState == 4 && asynchRequest.status == 200) {
        var response = JSON.parse(asynchRequest.responseText);
        console.log(response.parse.title); //--> Afficher le titre de la page
        console.log(response.parse.images); //--> Afficher les images contenues dans cette page
    } 
};

//Déclarer les détails de la requête
var eduTechWikiPage = "https://edutechwiki.unige.ch/fmediawiki/api.php?action=parse&page=JavaScript&format=json";
asynchRequest.open("GET", eduTechWikiPage, true);

//Envoyer la requête
asynchRequest.send();

//Message pour montrer la requête asynchrone
console.log("Ce message va s'afficher en premier même s'il apparaît en dernier dans le code source");

Le résultat à la console de cette requête sera similaire à ça :

Ce message va s'afficher en premier même s'il apparaît en dernier dans le code source
JavaScript
["JavaScript_exemple_alert.png", "JavaScript_trois_niveau_js.png", "JavaScript_as_a_controller.png"]

La partie importante de ce code réside principalement dans la fonction qui est associée à asynchRequest.onreadystatechange. Cette fonction est un gestionnaire d'événement de l'événement onreadystatechange qui détermine l'état de la requête. Cet état peut avoir les valeurs suivantes :

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

Dans le code, on veut afficher le message seulement si la requête est terminée, c'est-à-dire qu'elle a atteint le state 4.

L'état de la requête détermine exclusivement quel point est atteint par le processus, mais ne garantie pas qu'on a obtenu une réponse satisfaisante. On pourrait très bien obtenir un état de type 4 même avec une page qui n'existe pas. C'est pour cette raison qu'on s'intéresse également au status de la réponse. Ces status peuvent avoir différents numéros à trois chiffres (voir la liste complète sur Wikipedia). La première chiffre détermine le type de réponse obtenues :

  • 2xx --> Réponse OK
  • 3xx --> Redirection d'une autre page
  • 4xx --> Erreur au niveau client (e.g. 404 --> Page not found)
  • 5xx --> Erreur au niveau serveur (i.e., le site ne marche pas)

Dans le code, on veut afficher le message seulement si notre requête a reçu une réponse satisfaisante, plus précisément un status 200 (OK).

Fetch API

var url = 'https://edutechwiki.unige.ch/fmediawiki/api.php?action=parse&page=JavaScript&format=json';
fetch(url).then(function(response) { 
   console.log(response.json()) 
});

Bibliothèques JavaScript

jQuery

jQuery met à disposition des méthodes pour faciliter les requêtes asynchrones (de manière générale, ce n'est pas limité à JSON). Pour bénéficier de ces méthodes il faut bien entendu d'abord inclure la bibliothèque (voir les instructions sur la page jQuery).

Voici un exemple qui utilise la même requête illustrée avec du vanilla JavaScript et qui utilise la méthode $.ajax() :

$.ajax({
    url: 'http://edutechwiki.unige.ch/fmediawiki/api.php',
    data: {
        action: 'parse',
        page: 'JavaScript',
        format: 'json'
    },
    dataType: 'jsonp',
    success: function (response) {
        console.log(response.parse.title);
        console.log(response.parse.images);
    }
});

Ce type de syntaxe permet de déterminer, entre autre, les arguments à passer à la requête à travers la propriété data. Ensuite on peut déterminer le format de la réponse à travers dataType. Veuillez noter que dans cette exemple on a utilisé le format jsonp et non pas json pour contourner la restriction du same origin policy (voir plus haut). Enfin, à travers la propriété success on peut déterminer la fonction qui s'occupe de prendre en charge le contenu de la réponse.

Il existe également un raccourci qui utilise directement la méthode $.getJSON(). Voici le même exemple que plus haut. Veuillez noter que dans ce cas, pour contourner la same-origin policy, on ajoute un paramètre ..&callback=? à la fin de l'URL pour "simuler" le format JSONP.

var eduTechWikiPage = "http://edutechwiki.unige.ch/fmediawiki/api.php?action=parse&page=JavaScript&format=json&callback=?";
var jqxhr = $.getJSON(eduTechWikiPage, function (data) {
        console.log(data.parse.title);
    });

Exemples d'applications et d'utilisation

La liste serait très longue puisque la plupart des applications web 2.0 de type RIA sont crées avec AJAX.

Il faut aussi rappeler que certaines applications web traditionnelles utilisent quelques composants AJAX, par exemple la plateforme Moodle (version 2008) permet de déplacer des éléments de cours.

Liens et bibliographie