AJAX Cross Domain et Cross Browser à la Google Suggest

WRInaute discret
A propos de Google Suggest, implémenté ces jours-ci par défaut.

Regardez comme c'est astucieux, leur façon de faire des requetes asynchrones.

Au lieu d'utiliser de l'AJAX de base avec XMLHttpRequest(), ils utilisent la méthode suivante :

1) à chaque caractère tapé, ils injectent dans le HEAD de la page un javascript généré dynamiquement. ça génére donc des requetes sur leur server, et ça ressemble à ça :

Code:
http://clients.google.com/complete/search?hl&q=colo
http://clients.google.com/complete/search?hl&q=coloc
http://clients.google.com/complete/search?hl&q=coloca
http://clients.google.com/complete/search?hl&q=colocat
http://clients.google.com/complete/search?hl&q=colocatr
etc ...

2) Ce javascript est généré de la façon suivante (j'ai simplifié le code pour qu'il soit plus lisible)

une première fois :

Code:
<SCRIPT>
window.setTimeout(function() {
    var xjs=document.createElement('script');
    xjs.src='monscript_a_injecter_dans_le_head.js';
    document.getElementsByTagName('head')[0].appendChild(xjs);
}, 0)
</SCRIPT>

Dans le head, on se retrouve à la fin avec un truc comme ça dans le DOM :

Code:
<SCRIPT id="gac_a" src="http://clients1.google.com/complete/search?hl=fr&amp;q=coloca"></SCRIPT>

puis, il leur suffit de changer la source du script en modifiant l'object "gac_a" (avec SetAttribut('src', 'nouvelle url') je suppose)

3) Cette requete renvoit alors un code javascript qui ressemble à ça :

Code:
window.google.ac.h(["colocatri",[
    ["colocatrice","61,300 résultats","1"],
    ["colocatrices.com","36,400 résultats","2"],
    ["colocatrice.com","380 résultats","3"],
    ["colocataires.fr","6,310 résultats","4"],
    ["colocataires .com","47,200 résultats","5"],
    ["colocataire paris","729,000 résultats","6"],
    ["colocation","11,800,000 résultats","7"],
    ["colocatrice dictionnaire","157 résultats","8"],
    ["colocataire.fr","4,800 résultats","9"],
    ["colocataire","783,000 résultats","10"]
]])

4) la fonction ac.h() est alors excécutée et se charge d'updater l'UI (le display du suggest)

C'est vraiment très très astucieux, ça permet de faire de l'AJAX Cross-Browser sans se soucier du navigateur et sans requete du type XMLHttpRequest().

Et bien sur .... c'est 100% Cross-Domain puiqu'on peut utiliser cette technique pour aller lire du JS sur un autre domaine : http://www.autredomaine.com/mon_script_cross_domain.js

Vraiment sympas cette façon de faire, qu'en pensez vous ?
 
WRInaute passionné
moi qui croyait être le seul à m'y être intéressé ^^

Pour compléter, par défaut on ne peut pas faire de ajax d'un site à un autre, c'est considéré comme une faille de sécurité, en effet, çà pourrait permettre à des personnes mal attentionné de rapatrier des données sur d autres serveurs ....

C'est donc cool, que des gros comme Google, utilise ce genre de techno / astuce, vu leur affinité avec Mozilla. Au moins on sait qu'on peut utiliser cette façon de faire sans avoir à se demander si elle sera toujours valable à la sortie du prochain navigateur.

en complément
http://www.xml.com/pub/a/2005/12/21/jso ... t-tag.html

sans compter, que ce script est un sacrément bon moyen pour eux de ne pas surcharger leur serveur principal .. et pour nous de nous assurer qu on garde de bon temps de réponse (dans le cas ou on désactive le gadget)
 
WRInaute impliqué
Salut,

Merci pour cette étude, j'ai trouvé ton post très instructif (d'autant plus que je suis loin d'être une bête de guerre en js).
 
Nouveau WRInaute
Merci pour ces infos très utiles.
Mais qu'en est-il de la compatibilité de cette méthode par rapport à l'utilisation à la "ajax" habituelle, pour ce qui concerne les navigateurs un peu exotiques ou plus anciens ?
 
WRInaute discret
Voila, j'ai un peu bossé dessus et j'ai fait une petite librairie JavaScript très simple d'utilisation, et voici donc le résultat si ça intéresse quelqu'un.

So : A Simple Cross-Browser Way To Make Cross-Domain HTTP Requests without AJAX, using Dynamic JavaScript Streaming

En français : un moyen simple et Cross-Browser d'effectuer des requêtes HTTP Cross Domain, sans AJAX, en utilisant des injections dynamiques de flux JavaScript.


1) Créez un fichier nommé squeere_http.js, et mettez ça dedans :

Code:
function SqueereHTTP(url, instance) {
	this.loaded = false;
	this.url=url;
	this.script;
	this.firstparam=true;
	this.serverResponse;
	this.instance=instance;
	that=this;
	

	this.AddParam = function(p, v) {
		if (that.firstparam) {
			that.url+='?'+p+'='+v;
			that.firstparam=false;
		} else {
			that.url+='&'+p+'='+v;
		}
	}

	this.Request = function(force) {
		that.AddParam('instance', that.instance);
		if (force) {
			var axd = new Date();
			var shake = axd.getDate()+""+axd.getMonth()+1+""+axd.getFullYear()+""+axd.getHours()+""+axd.getMinutes()+""+axd.getSeconds();
			that.AddParam('squeereshaker', shake);
		}
		that.script = document.createElement('script');
		that.script.setAttribute('charset','UTF-8');
		that.script.setAttribute('type','text/javascript');
		that.script.setAttribute('src', that.url);
		that.script.onload = that.onLoad;
		that.script.onreadystatechange = that.onLoad;
		document.getElementsByTagName('head')[0].appendChild(that.script);
	}

	this.onComplete = function(serverResponse) { }

	this.onLoad = function() {
		if (that.loaded) { return; }
		that.loaded=true;
	};

	return this;
}


2) Mettez ça dans un fichier nommé client.html
Il s'agit d'un exemple de code client pour la établir une connexion à votre serveur distant.

Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Document sans titre</title>
<script language="javascript" src="squeere_http.js"></script>
</head>

<body>

<input name="dfgfdg" type="button" value="Request"  onclick="myReq.Request(true);"/>

<script type="text/javascript">

	var myReq;

	myReq = new SqueereHTTP('http://www.monsite.com/_test_http.php', 'myReq');
	myReq.AddParam('age', 29);
	myReq.AddParam('color', 'blue');

	myReq.onComplete = function(serverResponse) {
		var json = eval('(' + serverResponse + ')');

		var rep='';
		for(var param in json) {
			rep += param+' = '+json[param]+'\n';
		}
		alert(rep);
		
		alert(json.response);
		alert(json.param1);
		alert(json.param2);
		alert(json.color);
	}

</script>

</body>
</html>


3) et enfin, le code pour le serveur (cross domain parfaitement possible bien évidement ;-)
mettez ça dans un fichier nommé _test_http.php et mettez le fichier sur n'importe quel site, par exemple http://www.mon_autre_site.com/_test_http.php

Code:
<?php
// -----------------------------------------------------------------------
if (isset($_GET['instance'])) {$instance=$_GET['instance'];} else {die();}
// -----------------------------------------------------------------------
if (isset($_GET['age'])) {$age=$_GET['age'];} else { $age=0; }
if (isset($_GET['instance'])) {$instance=$_GET['instance'];} else {die();}


$json = array();
$json['response'] = "Yo, I'm the response from CrossDomainSite.com";
$json['param1'] = 123;
$json['param2'] = 456;
// ...
$json['color'] = '#FF0000';
// --------------------------------------------------------------

$params = json_encode($json);
echo($instance.".onComplete('".addslashes($params)."');");
?>


Attention, ce code utilise json_encode, ça marche donc par défaut avec PHP 5.2 +
Si vous ne disposez pas de json_encode, remplacez les valeurs à la main, ce qui, dans l'exemple ci-dessus, donnerait un truc comme ça :

$params = '{"response":"Yo, this is CrossDomainSite.com","param1":123,"param2":456,"color":"#FF0000"}';

Donc, faut sérialiser à la main si json_encode n'est pas présent dans votre version de PHP.



N'oubliez pas de changer l'url du serveur dans le fichier client.html
myReq = new SqueereHTTP('http://www.monsite.com/_test_http.php', 'myReq');

en indiquant bien l'adresse de votre serveur distant.

Voila !
 
Nouveau WRInaute
Bonjour,
j'ai testé cette lib dans l'idée de faire de l'Ajax "sans ajax" (je cible un javascript sur un domaine different), et j'obtiens un bon résultat sur IE 6.
Par contre le comportement n'est pas du tout asynchrone sur IE 7 et Firefox.
Est ce que cette actuce a été récement interdite (interpretée comme un contournement pour faire de l'ajax déguisé, donc une faille ?)

merci d'avance si vous avez la réponse

edit 29/09/2008
Ok la technique décrite est asynchrone parce qu'elle est appelée par un onclick.
si on ne veut pas déclencher sur une action du visiteur il faut démarrer sur un window.onload par exemple.
c'est seulement a ce prix qu'on aura un "effet asynchrone" qui pourrait passer pour de l'AJAX.
 
Nouveau WRInaute
Hello !

Je n'ai pas d'accès FTP pour le moment (je suis nouveau dans la boîte), mais j'aimerais tester cela. Quelqu'un pourrait t'il me dire si il a hébergé la fichier _test_http.php, et si je peux me permettre de l'utiliser pour mes tests ?

Merci d'avance !
A.
 
Discussions similaires
Haut