AJAX

Client/serveur

Coté Client...

Dans le cas simple

  • L'utilisateur rentre l'adresse d'une page internet dans la barre d'adresse
    • Pointe sur une ressource
  • Le navigateur
    • fait un appel HTTP pour récupérer la page HTML
    • décode la page HTML en un arbre DOM
    • liste les ressources à aller chercher en plus: CSS, images
    • fait autant d'appels HTTP que nécessaire
    • puis traite les réponses:
      • Images et CSS: appel au moteur de rendu
    • attend que l'utilisateur clique sur un lien

On est donc dans un mode statique:
Le navigateur ne fait rien de plus qu'afficher du contenu

Coté Client...

Cas dynamique

  • Les ressources ne sont plus uniquement HTML+CSS+Images
    • Mais aussi des scripts Javascripts
  • Ces scripts tournent sur le navigateur, en local
  • On peut débrancher internet, ça va quand même marcher...
    • (Sauf le script fait des appels HTTP)
  • Les scripts peuvent eux-même faire des appels HTTPs
    • Non pas des pages HTML, mais des données structurées
    • Ou, plus généralement, une interaction avec des services web
  • L'ensemble HTML+CSS+Images+Javascript est un programme autonome
    • qui tourne sur le navigateur
    • Pensez: gestion de mail, calendrier, jeu, etc.

Requête GET

  • Paramètres dans l'adresse
    http://www.domaine.com?param1=val1&param2=val2&param3=val3
  • Pour interroger un serveur
  • Indexable

Requête POST

  • Paramètres dans le corps de la requête
  • Pour envoyer des informations au serveur

Coté Serveur...

  • Une machine connectée au Web
  • Avec un programme qui tourne dessus...
  • Et qui écoute sur un port de la machine
  • Lors d'une connection avec une requête HTTP, il produit une réponse HTTP
    • Le contenu d'un fichier (mode statique)
    • Ou une donnée structurée: mail, agenda, etc (mode dynamique)
    • Voire un simple ACK (mise à jour d'une BDD par exemple)

Exemple

Essayons avec ce lien, et cet autre lien, et encore cet autre lien.

AJAX

Asynchronous
JAvascript and XML

  • Execution d'une requête avec javascript
  • Sans changer de page
  • Page web = une application!

Exemples: Partout

  • Tous les webmails
  • Google Map: chargement des tuiles à la volée
  • Suggestions dans les moteurs de recherche
  • Les "listes infinies" de résultats
  • ...

Requête Synchrone

Page bloquée en attendant les résultats

Requête Asynchrone

Pas de garantie dans l'ordre d'arrivée du résultat des requêtes

Requêtes inter-domaine

  • "Same Origin Policy"
  • Pas d'appel XmlHttpRequest à un site arbitraire
  • Pour des raisons de sécurité

Pour pouvoir le faire

  • Proxy sur le serveur
  • Configuration serveur CORS (Cross Origin Resource Sharing)
    un HTTP particulier: Access-Control-Allow-Origin
  • Le hack JSONP (mais pas recommandé)

Asynchronicité: Callback

En programmation AJAX:
  • Une page web est un programme
  • qui réagit à des évènements:
    • Click de souris
    • Chargement de page
    • .... réception d'une réponse à une requête HTTP
  • Pour réagir: fonction de callback
someDOMelement.addEventListener("click",function(e){
   // what to do on a click --> THIS IS A CALLBACK FUNCTION
},false);

Asynchronicité: Callback

Problème: peu lisible en cas de chainage. Imaginons

  • affiche(meteo,callback) : affiche la météo et appelle callback
  • appelAJAXmeteoVille(ville,callback) : appel AJAX pour la météo de ville
  • appelAJAXgeoLoc(gps,callback) : appel AJAX pour trouver la ville associé à gps
appelAJAXgeoLoc(gps, function(ville) {
  appelAJAXmeteoVille(ville, function(meteo) {
    affiche(meteo, function() { console.log('OK') })
  });
})

Asynchronicité: Promesses

Une promesse est un objet (Promise) qui représente la complétion ou l'échec d'une opération asynchrone.

C'est à lui qu'on attache des callbacks plutôt que de passer ces callbacks à une fonction.

Asynchronicité: Promesses

Avec des promesses

appelAJAXgeoLoc(gps) : quand on lui applique la méthode .then(fun), exécute la promesse et donne le résultat à fun.

appelAJAXgeoLoc(gps).then(function(ville) {
  return appelAJAXmeteoVille(ville);
})
.then(function(meteo) {
  return affiche(meteo);
})
.then(function() { 
  console.log('OK');
})
.catch(failureCallback);

Asynchronicité: Promesses

Avec des promesses

appelAJAXgeoLoc(gps)
.then(ville => appelAJAXmeteoVille(ville))
.then(meteo => affiche(meteo))
.then(() => { console.log('OK'); })
.catch(failureCallback);

Asynchronicité: Promesses

Avec des promesses

appelAJAXgeoLoc(gps)
.then(appelAJAXmeteoVille)
.then(affiche)
.then(() => { console.log('OK'); })
.catch(failureCallback);

Fetch API

L'API Fetch fournit une interface JavaScript à base de promesses pour les requêtes et les réponses HTTPs.

Ce genre de fonctionnalité était auparavant réalisé avec XMLHttpRequest en Javscript pur.

Une alternative consiste à utiliser la librairie jQuery.

Fetch API

Requête avec fetch():

const myImage = document.querySelector('img');

fetch('flowers.jpg')
.then(function(response) {
  return response.blob();
})
.then(function(myBlob) {
  const objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

L´objet response

De la classe Response. Méthodes interessantes:

  • .blob() : pour une image
  • .text() : pour du texte
  • .json() : pour du json ! (voir plus loin)

XML et JSON

Origine

besoin d'échanger des données entre acteurs

  • Données bancaires
  • Données de remboursement de santé
  • Description d'une recherche d'itinéraire dans Google Maps
  • La réponse associée: description d'un itinéraire
  • ...

D'où la nécessité d'un format de structuration universel

  • Pour toutes sortes de données structurées
  • Lisible sur tous les systèmes
  • Le plus simple possible

XML

Généralisation de HTML

HTML

  • Document texte
  • Structure figée
  • Un langage

XML

  • Données arborescentes
  • Structure libre
  • Un meta-langage

XML versus HTML

Arbre XML

Syntaxe

  • Même syntaxe que HTML
  • Toute balise doit être refermée explicitement
  • Notion de bonne formation
    <a></b>   <!-- Non valide ! -->
  • Un prologue
    <?xml version="1.0" encoding="UTF-8"?>

Grammaire

  • Bonne formation = description d'un arbre
  • Mais pas nécessairement avec la bonne structure
  • Rôle d'une grammaire
    • Doctype (voir l'entête HTML)
    • Schéma XML (XSD)
  • Voir le tuto sur la validation XML

Espaces de Nom

  • Distinguer les éléments/attributs issus de divers vocabulaires
  • Cibler le processeur XML adapté au langage
  • Un espace de nom est une chaine de caractères
    XHTML
    "http://www.w3.org/1999/xhtml"
    MathML
    "http://www.w3.org/1998/Math/MathML"
    SVG
    "http://www.w3.org/2000/svg"
    RDF
    "http://www.w3.org/TR/REC-rdf-syntax#"
    Dublin Core
    "http://purl.org/dc"

Association

<?xml version=”1.0”?>
<catalog>
 <rdf:RDF xmlns:rdf=”http://www.w3.org/TR/REC-rdf-syntax#”>
  <rdf:Description about=”http://mon-catalogue” xmlns:dc=”http://purl.org/dc”>
   <dc:title>Tableaux impressionistes</dc:title>
   <dc:creator>Benoît</dc:creator>
   <dc:description>Liste de tableaux célèbres</dc:description>
   <dc:date>2009</dc:date>
  </rdf:Description>
 </rdf:RDF>
 <painting>
  <title>Souvenir d'un jardin à Eden</title>
  <artist>Van Gogh</artist>
  <date>1888</date>
  <description>Deux femmes regardent sur la gauche ;
    une troisième travaille au jardin.</description>
 </painting>
 ...
</catalog></code>

Quelques règles

  • Certains préfixes sont canoniques, comme dc, rdf, svg.
  • On peut aussi utiliser xmlns seul. Par exemple:
    <svg xmlns=”http://www.w3.org/2000/svg” width=”12cm” height=”10cm”>
      <ellipse rx=”110” ry=”130”/>
      <rect x=”4cm” y=”5cm” width=”3cm” height=”4cm”/>
    </svg>
  • Dans ce cas, tout le sous-arbre est dans l'espace de nom

JSON

  • Un format plus simple
  • Mais beaucoup moins riche
  • Issu d'un développement propriétaire en 2006, standardisé ensuite
  • Sous-ensemble de JavaScript (littéraux)
    • Chaines de caractères
    • Tableaux
    • Objets (tables d'association)
  • Pas de notion de validation

Exemple

{
  "firstName": "John",
  "lastName" : "Smith",
  "age"      : 25,
  "address"  : 
  {
    "streetAddress": "21 2nd Street",
    "city"         : "New York",
    "state"        : "NY",
    "postalCode"   : "10021"
  },
  "phoneNumber": 
  [
    { "type"  : "home", "number": "212 555-1234" },
    { "type"  : "fax",  "number": "646 555-4567" }
  ]
}

Utilisation

  • À l'origine: utilisation de la fonction eval() de javascript
  • Mais grosse faille de sécurité
  • Plutôt: utilisation d'une librairie
    • JSON.stringify(objet)
    • JSON.parse(chaine de caractères)

Exemple: données structurées

Exemple avec Fetch

fetch('https://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=22e21ef649526ef2b1be4db6d2b0857d&mode=json')
.then(function(response) {
  return response.json();
})
.then(function(data) {
  alert(data.weather[0].description)
});