L'XMLHttpRequest cross-domain

Introduction

Avant de parler d'XMLHttpRequest cross-domain, il est nécessaire de définir ce qu'est le principe cross-domain.

Le cross-domain

Cross-domain signifie croisement de domaine. C'est un principe qui vise à faire communiquer deux domaines ensemble. Par exemple, monsite.com peut envoyer des données à tonsite.com, tout comme ce dernier peut renvoyer des données à monsite.com.

La plupart des techniques AJAX ne sont pas cross-domain pour des raisons évidentes de sécurité. Pour qu'une application cross-domain fonctionne, il faut que le domaine qui reçoit la requête soit autorisé à la traiter. C'est une mesure de sécurité obligatoire.

Image utilisateur

Il faut donc que le domaine à qui la requête est envoyée soit autorisé à répondre. Pour ce faire, on utilise l' Access Control , qui sera détaillé par la suite.

XMLHttpRequest et XDomainRequest

Faire communiquer deux scripts présents en des domaines différents est impossible avec XMLHttpRequest, dans sa spécification première.

Tous les navigateurs implémentent XMLHttpRequest dans sa spécification première (Level 1) qui ne permet pas de faire du cross-domain. Le W3C travaille sur la spécification 2 (Level 2) qui autorise le cross-domain.

Différences de point de vue

Pour résumer, pendant que le W3C travaille sur la deuxième spécification d'XMLHttpRequest, Microsoft implémente dans Internet Explorer 8 sa propre version du cross-domain, baptisée XDomainRequest. Microsoft justifie ce choix par le fait que la nouvelle version d'XMLHttpRequet ne le satisfait pas. La grosse différence entre XDomainRequest (XDR) et XHR est que ce n'est pas le même objet qui est utilisé, ce qui permet de ne pas s'embrouiller et de bien différencier les deux techniques.

Je vais donc vous parler des deux techniques bien qu'elles ne soient pas encore vraiment utilisables, car seul IE8 gère XDomainRequest et... aucun autre navigateur ne gère la version 2 d'XMLHttpRequest.

On va commencer par voir comment instancier ce nouvel objet, pour nous verrons le fonctionnement d'Access Control.

XDomainRequest et XHR 2

XDomainRequest

XDomainRequest fonctionne grosso modo comme XMLHttpRequest, mais un peu plus simplement. Je ne vais pas rentrer dans les détails, c'est facile à comprendre :

var xdr = new XDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
}
xdr.open("GET", "http://www.foxycode.net/dev/ajax/XDomain_1.php");
xdr.send();

Ce qui change par rapport à XHR, c'est la propriété onload qui remplace et simplifie grandement onreadystatechange, readyState et status. Si onload est déclenché, c'est que tout est bon.

XMLHttpRequest 2

L'utilisation de l'objet XHR en cross-domain est exactement la même que celle que nous avons vue. L'objet a cependant été un peu simplifié en supportant l'évènement onload (comme XDR) et onloadstart.

Ainsi, on peut résumer un code XHR 2 comme ceci :

var xdr = new XMLHttpRequest();
xdr.onload = function() {
alert(xdr.responseText);
}
xdr.open("GET", "http://www.foxycode.net/dev/ajax/XDomain_1.php");
xdr.send();

C'est simplement le même code que pour en envoi XDomainRequest, il y a juste le nom de l'objet qui change.

Combinaison des deux

Comme pour XHR, on va faire une fonction pour instancier facilement un objet XHR cross-domain. Je vais garder le nom de Microsoft pour nommer la fonction histoire de bien différencier les deux systèmes (ce qui fait que je suis plutôt en accord avec la dénomination fournie par Microsoft).

function getXDomainRequest() {
var xdr = null;
if (window.XDomainRequest) {
xdr = new XDomainRequest();
} else if (window.XMLHttpRequest) {
xdr = new XMLHttpRequest();
} else {
alert("Votre navigateur ne gère pas l'AJAX cross-domain !");
}
return xdr;
}

Cela s'utilise donc de cette façon :

var xdr = getXDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
}
xdr.open("GET", "http://www.foxycode.net/dev/ajax/XDomain_1.php");
xdr.send();

Tout cela, c'est pour instancier un objet cross-domain. Voyons maintenant comment autoriser le serveur à répondre à la requête.

L'Access Control

Pour savoir si le domaine questionné est autorisé à répondre il suffit simplement de lui indiquer par le biais d'un en-tête :

<?php header("Access-Control-Allow-Origin: *"); ?>

L'en-tête Access-Control-Allow-Origin sert à définir le domaine pour lequel les données pourront être renvoyées. Dans mon exemple, l'astérisque signifie tous les domaines. Il est bien évidemment possible d'affiner cette sélection de domaines :

<?php
header("Access-Control-Allow-Origin: *"); // Tous les domaines
header("Access-Control-Allow-Origin: monsite.com"); // Seul monsite.com peut y accéder
header("Access-Control-Allow-Origin: free.fr"); // Les sous-domaines de Free.fr sont autorisés, donc nayi.free.fr y a accès
?>

L'Access Control est en réalité beaucoup plus vaste que cela. Mais pour les besoins du tutoriel, il n'y a que Allow-Origin qui nous intéresse. Le reste est à découvrir par vous même, mais n'est pas géré complètement par les navigateurs.

Il existe aussi une version pour XML d'Access Control , mais non supportée par Internet Explorer.

Exemple d'utilisation

Les données

Voici le fichier contenant les données. Il est hébergé sur www.foxycode.net et sera récupéré par le script sur nayi.free.fr :

<?php
header("Content-Type: text/plain");
header("Access-Control-Allow-Origin: *");
?>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed hendrerit fringilla dui.
Aenean malesuada, eros nec venenatis fringilla, ipsum mauris suscipit sem, nec semper velit dui nec felis.

L'appel

Le script ci-dessous se contente simplement d'aller questionner le fichier PHP hébergé sur foxycode.net :

<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Techniques AJAX - XDomainRequest</title>
<script type="text/javascript">
<!--
function getXDomainRequest() {
var xdr = null;
if (window.XDomainRequest) {
xdr = new XDomainRequest();
} else if (window.XMLHttpRequest) {
xdr = new XMLHttpRequest();
} else {
alert("Votre navigateur ne gère pas l'AJAX cross-domain !");
}
return xdr;
}
function sendData() {
var xdr = getXDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
}
xdr.open("GET", "http://www.foxycode.net/dev/ajax/XDomain_1.php");
xdr.send();
}
//-->
</script>
</head>
<body>
<p>
<input type="button" onclick="sendData();" value="Récupérer" />
</p>
</body>
</html>

Vous pouvez tester cet exemple à cette adresse avec la plupart des navigateurs récents comme Firefox 3.5, Internet Explorer 8, Google Chrome 3. Cela ne fonctionne pas dans Opera 10.5.

L'XMLHttpRequest cross-domain n'en est qu'à ses débuts. Il va falloir attendre un peu pour voir ce que ça va donner. La technologie peut cependant être pleinement utilisable avec Internet Explorer 8 donc peut servir pour des applications uniquement dédiées à Internet Explorer 8.

Quoi qu'il en soit, il faut attendre que les autres navigateurs commencent à implémenter cette nouvelle technologie. Mais la spécification d'XHR 2 n'étant pas terminée, il va falloir encore attendre un peu.