Applications synchrones
Action → Requête → Réponse HTML → Action → …
-
L’utilisateur demande une URL
GET /action?parametres HTTP/1.1 ...
-
Le server répond avec du HTML.
-
L’utilisateur quitte la page en
- Cliquant un lien,
- Cliquant un bouton de type
submit
, - rafraîchissant.
POST /autre_action?parametres HTTP/1.1 ...
-
Le server répond avec de l’autre HTML.
Et l’état ?
HTTP est sans état
Dans le Web 1.0, le server est le seul responsable du maintien de l’état
- dans la logique de l’application (URLs, requêtes, etc.)
- dans son stockage local (sessions, bases de données),
- chez le client (cookies).
Action → Requête → Réponse HTML → …
Dommage collatéral : le browser perd l’état (à l’exception de son stockage local) à chaque nouvelle action.
Démonstration : naviguez vers la racine, puis revenez.
Temps passé sur ces slides :
Navigation synchrone
Exemple synchrone
<form method='GET'
action='http://answers.yahoo.com/search/search_result'>
<input name='p' type='text' value='AJAX' />
<input type='submit' value='Ask' />
</form>
Navigation asynchrone
Exemple asynchrone
Navigation asynchrone
Quels éléments pour une navigation asynchrone ?
Action ≠ Requête
- JavaScript intercepte les actions (évènements) de l’utilisateur.
Requêtes asynchrones (XMLHttpRequest
)
- JavaScript peut initier une requête indépendamment des actions de l’utilisateur,
- Les requêtes n’interrompent pas la navigation.
Server push (EventSource
, Web sockets)
- Le serveur peut envoyer des données au client sans attendre une requête.
XMLHttpRequest
XMLHttpRequest
Introduit par Microsoft dans IE5, maintenant un standard W3C.
- Envoie des requêtes POST ou GET (ou autre) vers le server ;
- Ne bloque pas le browser en attendant la response ;
- Exécute une callback asynchrone à l’arrivée de la response.
/*************** Cliquez ! ***************/
mydiv.onclick = function() {
xhr = new XMLHttpRequest();
xhr.open("GET", "../LICENCE.md");
xhr.onload = function(event) {
alert(xhr.response);
}
xhr.send();
}
Creation et préparation
xhr = new XMLHttpRequest();
xhr.open("POST", "http://.../action?params");
Callbacks
xhr.onload = function(event) {
console.log('Succes');
}
xhr.onerror = function(event) {
console.log('Erreur');
}
xhr.onabort = function(event) {
console.log("Annulé par l'utilisateur");
}
xhr.onprogress = function(event) {
console.log('Téléchargement...');
}
Envoyer des données
xhr.setRequestHeader('Content-Type', 'text/plain')
xhr.send("Hello world !");
Simuler un formulaire (peut aussi envoyer des données binaires)
var formData = new FormData();
formData.append('q', 'AJAX');
formData.append('hl', 'en');
// Content-Type: multipart/form-data par defaut
xhr.send(formData);
Envoyer du JSON
var data = { primes : [2, 3, 5, 7],
even : [2, 4, 6, 8] };
xhr.setRequestHeader('Content-Type',
'application/json');
xhr.send(JSON.stringify(data));
Lire la réponse
xhr.onload = function() {
// Texte simple (indépendamment du type de la réponse)
console.log(xhr.responseText);
// XML (si la réponse est dans ce format)
console.log(xhr.responseXML);
// Variable (texte par défaut ?)
console.log(xhr.response);
}
Pré-traitement de la réponse par le browser
xhr.responseType = "json";
xhr.onload = function() {
var obj = xhr.response; // transformé en objet JavaScript
console.log(obj.toto); // par le browser
}
text
: texte,document
: DOM HTML,arraybuffer
,Blob
: données binaires.
L’API AJAX de JQuery
XMLHttpRequest
commence à être bien supporté, mais les frameworks
JavaScript offrent une interface simplifiée et compatible avec les
vieux browsers. En JQuery
$.ajax({
url : 'http://example.com/api/json/query',
type : 'GET',
// équivalent de responseType
dataType : 'json',
// conversion et gestion automatique de GET et POST
data : { car: 'peugeot', color: 'bleu' },
// Callbacks pour les évènements
success : function() { ... },
error : function() { ... },
complete : function() { ... }
});
- La requête est créée et envoyée en un seul coup,
- Utilise des noms non-standards pour les évènements,
- dans les callbacks
this
est rattaché à l’objet XHR.
Étude de cas : Yahoo answers
$('#yahoo').onsubmit = function(e) {
var query = $('#query').value;
var yql = encodeURIComponent(
"SELECT * FROM answers.search WHERE query='"
+ query + "'");
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://query.yahooapis.com/v1/public/yql'
+ '?format=json&diagnostics=true&callback=&q=' + yql);
xhr.onload = callback;
xhr.responseType = 'json';
xhr.send();
e.preventDefault();
}
- Récupération le contenu du champs de texte ;
- Préparation de la requête à http://query.yahooapis.com/v1/public/yql ;
- Préparation d’une interrogation au format YQL de Yahoo ;
- On attend un résultat au format JSON ;
- On arrête la soumission du formulaire.
Étude de cas : Yahoo answers
var callback = function(e) {
if (xhr.response) {
var liste = xhr.response.query.results.Question;
var q = liste[Math.floor(Math.random() * liste.length)];
$('#answers').innerHTML =
'<p><b>Question:</b> ' + q.Content + '</p>' +
'<p><b>Best answer:</b> ' + q.ChosenAnswer + '</p>';
} else {
$('#answers').innerHTML = '<p>Pas de résultats.</p>';
}
}
- La réponse (au format JSON) est automatiquement convertie en objet JavaScript ;
- On sélectionne une question au hasard ;
- On insère le résultat dans la page via le DOM.
Formats d’échange de données
Formats de données en AJAX
AJAX est l’acronyme de « Asynchronous JavaScript and XML ».
Mais chaque composant est optionnel, en particulier XML !
Selon l’application, l’un des formats suivants peut être mieux adapté qu’un autre :
- Pas de données : les entêtes HTTP suffisent ;
- Texte simple ;
- Extraits de HTML ;
- JavaScript, CSS, … ;
- JSON, autres formats légers (YAML, …) ;
- XML, autres formats structurés (HTML, …) ;
- Données binaires, encodage Base64, … ;
- …
Utiliser l’entête Content-Type
pour déclarer le format.
Texte ou rien
Pour des actions simples comme
- Sauvegardes automatiques (mails, documents, etc.),
- Avancement.
POST /api/save HTTP/1.1
Host: mail.google.com
...
Dear Sir,
It is my ple
HTTP/1.1 200 OK
Content-Type: text/plain
...
23
HTML
Pour une inclusion directe de fragments HTML (par ex., billets de blog, commentaires, …)
GET /?post=23389 HTTP/1.1
Host: www.wordpress.com
...
HTTP/1.1 200 OK
Content-Type: text/html
...
<article class='post' id='post23389'>
<p>I've always thought...
Exemple d’inclusion dans le document:
xhr.onload = function() {
$('#main').innerHTML = xhr.responseText;
});
Problème: Viole la séparation entre données, présentation et logique.
JavaScript
GET /api/car?user=toto HTTP/1.1
Host: www.example.com
...
HTTP/1.1 200 OK
Content-Type: application/javascript
...
{ car : 'peugeot',
color : 'blue' }
Exemple d’inclusion dans le document
xhr.onload = function() {
var res = eval(xhr.responseText);
}
Problèmes graves
- Viole la séparation de la logique ;
- Grande risuqe de failles XSS.
JSON
JSON est un sous-ensemble léger des types de données de JavaScript (nombres, chaînes, tableaux et objets)
GET /api/car?user=toto HTTP/1.1
Host: www.example.com
...
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "car" : "peugeot", "color" : "blue" }
Avantages / Désavantages
- Beaucoup plus compact que XML, facile et rapide à évaluer ;
- Moins puissant que XML ;
- Supporté par tous les browsers modernes ;
- Pas de risques d’évaluer du code dangéreux ;
- Peut créer une vulnérabilité XSS si évalué avec
eval()
.
XML
Pour des données riches et structurées (par ex., requêtes BD, geodata, …)
GET /v1/public/yql?q=SELECT * FROM geo.places WHERE text "Paris" HTTP/1.1
Host: query.yahooapis.com
...
(La requête a été légèrement modifiée pour faciliter la lecture)
HTTP/1.1 200 OK
Content-Type: application/xml
...
<?xml version="1.0" encoding="UTF-8"?>
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="10" yahoo:created="2012-03-14T04:38:52Z" yahoo:lang="en-US">
...
<results>
<place xmlns="http://where.yahooapis.com/v1/schema.rng" xml:lang="en-US" yahoo:uri="http://where.yahooapis.com/v1/place/615702">
<woeid>615702</woeid>
<placeTypeName code="7">Town</placeTypeName>
<name>Paris</name>
...
XML
Évaluation, manipulation
- XPath: Query language pour la sélection de nœuds dans un arbre XML ;
- XSLT (Extensible Stylesheet Language Transformations): transformations de documents XML.
Avantages / Désavantages
- Puissant, robuste ;
- Supporté par beaucoup de services web.
- Verbeux, relativement lent ;
- Peux d’implantations complètes ;
- Spécification énorme avec des risques de failles de securité.
Communication bidirectionnelle
Server push
Problème : AJAX est unidirectionnel
- Le client envoie des données dans la requête,
- Le server répond avec des données.
- Le server ne peut pas initier un transfert de données ;
- Le server ne peut pas appeler des fonctions (déclencher des évènements) chez le client.
Simuler une communication bidirectionnelle (Comet)
- Short polling, Long polling, Streaming.
Vraie communication bidirectionnelle
EventSource
, WebSockets.
Polling
Utile pour : notifications, compatibilité avec vieux browsers
Short polling
- Le client envoie une requête AJAX à intervalles réguliers (de l’ordre de la seconde),
- S’il y a des notifications depuis la dernière requête, le server les envoie dans la réponse.
Long polling, Streaming
- Le client ouvre une connexion HTTP avec le server,
- Le server envoie les entêtes mais ne ferme pas la connexion,
- Lorsque des notifications arrivent, le server les envoie dans la connexion ;
- (long polling) Le server ferme la connexion.
Polling
Avantages
- Compatible avec les vieux browsers,
- Ne demande pas de support spécifique chez le server.
Désavantages
- Gourmand en bande passante et ressources (overhead du protocole HTTP),
- Latence.
Event stream
Format de streaming unidirectionnel Server → Client : la connexion reste ouverte
HTTP/1.1 200 OK
Content-Type: text/event-stream
...
data: un message
data: un autre
data: message
event: toto
data: un message avec un nom
data: { "msg" : ["Porquoi", "pas", "du", "JSON"] }
- Un message d’une ligne,
- Un message sur plusieurs lignes,
- Un message nommé,
- On est libres de choisir le format des données.
EventSource
Le client est notifié des messages du server par des évènements
var evt = new EventSource("/api/notifications");
// Messages sans nom
evt.addEventListener('message', function(e) {
console.log(e.data);
});
// Messages nommés
evt.addEventListener('toto', function(e) {
console.log('Évènement nommé :', e.data);
});
- Pro : Léger, Simple,
- Contre : Unidirectionnel, Nécessite le support du server,
- Démo : http://server-sent-events-demo.herokuapp.com/.
Web Sockets
Protocole de communication full-duplex, compatible avec HTML
- Protocole applicatif au dessus de TCP : pas de overhead HTTP ;
- Conçu pour utiliser le même port que HTTP (port 80 par défaut).
GET /app/socket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
...
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
...
- Le client demande une connexion web socket,
- Le server répond avec
101 Switching Protocols
, - Le server et le client établissent une connexion TCP de type Web Socket.
Web Sockets
Avantages
- Bidirectionnels,
- Peu de overhead.
Désavantages
- Nécessitent de support dans le server,
- Pas adaptés au modèle d’exécution Apache+PHP.
En pratique
Utiliser des bibliothèques qui abstraient du mécanisme utilisé (Web Sockets, Flash, …).
- Node.js : http://socket.io/ (très simple à utiliser),
- PHP : http://socketo.me/ (très difficile à configuer).
Applications REST
Applications REST
REST (Representational State Transfer) est un paradigme pour les applications distribuées
- Client-Server (pas de peer-to-peer) ;
- Sans état (au contraire de CORBA, par ex.) ;
- Cacheable ;
- Par niveaux (c.-à-d.., compatible avec l’utilisation de proxies) ;
- Interface uniforme (verbes GET, POST, PUT, DELETE, …).
En pratique
- Une application web REST exploite au maximum l’expressivité du protocole HTTP ;
- Tous les services RESTful sont basés sur HTTP.
Avantages: Simplicité, Scalabilité.
APIs REST
Après un long monopole des interfaces SOAP, beaucoup de services web migrent maintenant vers des APIs REST
- Google APIs: http://code.google.com/more/ ;
- Open Street Maps: http://wiki.openstreetmap.org/wiki/API (geodata, cartes) ;
- Amazon: http://aws.amazon.com/ ;
- The Weather Channel: http://www.weather.com/services/xmloap.html ;
- Facebook: http://developers.facebook.com (authentification, graphe social) ;
- Yahoo: http://developer.yahoo.com/ ;
- …
La majorité de ces APIs offre des interfaces XML et JSON.
Essayez la Console YQL de Yahoo !
Lectures
AJAX, XMLHttpRequest
- Tutoriel MDN
XMLHttpRequest
, - Tutoriel MDN
FormData
, - Manuel de JQuery : http://api.jquery.com/.
JSON
- Définition de JSON : http://www.json.org/,
- Guides MDN.