JSONP (cross-domain AJAX) – zdalny AJAX spoza domeny

Zwykły AJAX operujący na obiekcie klasy XMLHttpRequest umożliwia połączenie się jedynie z zasobami znajdującymi się w obrębie tej samej domeny. Z tego właśnie powodu, poniższy skrypt nie zadziała.

//Wywołanie na domenie: example1.pl
http = new XMLHttpRequest();
http.open('GET', 'http://example2.pl/index.html', true);

Powodem takiego zachowania są kwestie bezpieczentwa. Istnieje jednak kilka metod na obejście tego zabezpieczenia. Jedną z nich jest właśnie opisywany w tym artykule JSONP. W tej metodzie wykorzystuje się fakt, że przeglądarka może z dowolnej domeny pobrać kod JavaScript. Pokazuje to poniższy przykład.

<script type="text/javascript" src="http://jakasDomena.pl/skrypt.js" />

I teraz przechodzimy do meritum. W technice JSONP chodzi o to, aby przekazać dane właśnie poprzez kod JavaScipt. Nie możemy jednak tego zrobić poprzez zwykłe przypisanie danych do zmiennej, gdyż zmienna z dołączonego pliki JS nie będzie widoczna w naszym lokalnym kodzie JS. Możemy jednak zrobić to inaczej. Rozważmy przykład.

<html>
	<head>
		<script>
			function doit(dane) {
				alert(dane);
			}
		</script>
 
		<script src="skrypt.js">
		</script>
	</head>
</html>

Mamy taką przykładową stronę WWW. Jak widać zdefiniowana jest tu przykładowa funkcja o nazwie doit, która w tym przypadku wyświetla na ekranie przekazany parametr. Dalej ładujemy zdalny skrypt JS, który wygląda tak jak poniżej.

doit('zdalne dane');

W rezultacie zdalny skrypt wywołuje lokalną funkcję przekazując jej parametr, który jest w rzeczywistości odpowiednikiem danych pobieranych w lokalnym ujęciu przez AJAXa.

Analogiczny efekt można uzyskać w trochę inny sposób. Pokazuje to poniższy przykład.

<html>
	<head>
		<script>
			function doit(dane) {
				alert(dane);
			}
 
			var jsonp = document.createElement('script');
			jsonp.src = 'skrypt.js';
			document.head.appendChild(jsonp);
		</script>
	</head>
</html>

Jak widać, efekt jest ten sam, tylko zamiast statycznie wpisanego elementu SCRIPT mamy dynamicznie utworzony i dodany takowy element. Taki dynamiczny element można zamiast do HEAD dołączyć do BODY, ale wtedy powyższy kod musi znajdować się również w BODY, gdyż w przeciwnym razie wystąpi sytuacja, że kod z HEADa nie będzie wiedział jeszcze o istnieniu sekcji BODY i będzie generował błąd.

W bardziej zaawansowanych przypadkach, kod ze zdalnego pliku JS jest generowany dynamicznie przez parser PHP. Nazwa lokalnej funkcji oraz rodzaj danych, które chcemy otrzymać mogą być wtedy przekazane do PHP za pomocą parametrów GET, które wpisane są w URL zdalnego pliku JS. Ilustruje to poniższy przykład wykorzystujący dodatkowo format danych JSON.

<html>
	<body>
		<script>
			function doit(dane) {
				json = eval('(' + dane + ')');
				alert(json.id);
			}
 
			var jsonp = document.createElement('script');
			jsonp.src = 'skrypt.php?fun=doit';
			document.body.appendChild(jsonp);
		</script>
	</body>
</html>

A kod generyjący skrypt JS za pomocą PHP:

<?php
	$fun = $_GET['fun'];
	$data = '{"id": 1}';
 
	echo $fun . "('" . $data . "');";
?>

Na koniec – jako ciekawostkę – powiem tylko, że opisywaną tu technikę wykorzystuje dołączany do strony kod Google Analytics.