Jakiś czas temu termin AJAX zmienił oblicze internetu, technologia choć była już znana otrzymała wsparcie wsród najbardziej popularnych (ówcześnie) przeglądarek internetowych. Coż to takiego ten AJAX ? W skrócie umożliwił on twórcą stron internetowych odbieranie oraz wysyłanie danych bez potrzeby przeładowania strony internetowej. Dzięki temu oceniając ciekawy clip na Youtubie lub dodajac komentarz na Facebook-u nie musimy czekać na ponowne załadowanie serwisu, ponieważ dane zostały wysłane przez przeglądarke w tle za pomocą Javascriptu. Pojawił się jednak problem z bezpiczeństwem, związany z możliwościa wysyłania danych wprost od użytkownika na dowolny server istniejący w sieci. Producenci przeglądarek w odpowiedzi na rosnącą liczbe ataków na serwisy internetowe wprowadzili ograniczenie uniemożliwiające wysłanie lub pobranie danych przy pomocy AJAX-a z innej domeny niż ta na której umieszczony jest serwis. W skrócie skrypt:
http = new XMLHttpRequest();
http.open('GET','http://niefrontend.com/obsluga_ajaxa.php',true);
nie zadziała, a przynajmniej nie wszędzie (działa na urządzeniach mobilnych wspierających js). Przeglądarka nie zgodzi się na dostęp do domeny niefrontend.com ponieważ (o ile taka domena istnieje) nie jest tą samą domena z której została załadowana aplikacja.
W tej sytuacji pada pytanie: i co teraz ? co jesli nasza apliacja pracuje w dość skomplikowanej architekturze i potrzebujemy zebrać dane z różnych źródeł ? co jeśli tworzymy api w Javascripcie które może być użyte na dowolonej stronie w sieci ?. Odpowiedzią na te pytania jest właśnie JSONP.
W świecie JSONP musimy na chwile zapomnieć o obiekcie XMLHttpRequest i przekierować uwagę na mechanizmy HTML-a a mianowicie na dobrze wszystkim znany tag <script>. Przypuśćmy że mamy potrzebe załadowania danych z hipotetycznej domeny niefrontend.com. Możemy to zrobić dynamicznie umieszczając tag w naszym dokumencie
var jsonpScript = document.createElement('script');
jsonpScript.src = 'http://niefrontend.com/obsluga_jsonp.php.js';
function obslugaDanych(dane){
//robimy cos z danymi może alert
alert(dane.daneJson);
}
document.body.appendChild(jsonpScript);
Na domenie niefrontend.com pod obsluga_jsonp.php.js przy odpowiedniej konfiguracji Apache-a kryje sie skrypt PHP ktory mógłby wyglądać tak:
<php?
echo "obslugaDanych({
daneJson:"przykładowy string"
});"
?>
W rezultacie do naszego dokumentu zostanie dołączony nastepujący HTML:
<body>
<script src="http://niefrontend.com/obsluga_jsonp.php.js">
obslugaDanych({daneJson:"przykładowy string"});
</script>
</body>
W momenecie dołączenia do dokumentu skypt zostanie automatycznie uruchomiony co za tym idzie nasza niesamowita funkcja do obsługi danych zostanie wywołana razem z danymi które odpowiednio przygotowaliśmy po stronie backendu. Cały sekret JSONP i cross-domenowego ładownaia danych sprowadza się do dynamicznego umieszczania tagów <script> które sa odpowiednio wypełniane danymi po stronie serwera. Wykorzystując podejście JSONP warto nie dopuścić do sytuacji w której większość naszego dokumentu bedą stanowić tagi typu <script>.
Ponieważ Javascript jest z natury asynchroniczny warto znać ten właściwy moment w czasie kiedy nasz skrypt zostanie załadowany oraz wykonany po to żeby sie go pozbyć. Można to zrobić informując skrypt żeby się usunął przy zdażeniu onload lub onreadystatechange (w przypadku Internet Explorera):
var jsonpScript = document.createElement('script');
jsonpScript.src = 'http://niefrontend.com/obsluga_jsonp.php.js';
jsonScript.onload = function(){
this.parentNode.removeChild(this);
}
//niestety Internet Explorer nie jest w stanie zrozumieć słowa 'onload' ale w zamian proponuje inne rozwiązanie
//które całkowicie jest ignorowane przez pozostałe przeglądarki
jsonScript.onreadystatechange = function(){
if(this.readyState=='loaded'){
this.parentNode.removeChild(this);
}
}
document.body.appendChild(jsonpScript);
Ciekawostką jest iż Internet Explorer nie jest w stanie zrozumieć słowa onload zamienia je na loaded i umieszcza je jako jeden ze stanów zdażeniu onreadystatechange. W zamian za to pozwala na obsługe wielu stanów ładowania skryptu. Aby nie pospieszyć się zbytnio i nie usunąć skryptu zanim zostanie wykonany, warto wiedzieć ze onreadystatechange jest wywołany wiele razy (w przeciwieństwie do onload ) natomiast stan loaded upewnia nas że w tym momencie skrypt napewno został załadowany i wykonany. Można go więc spokojnie usunąć.
Niestety JSONP posiada pewne wady i ograniczenia. Podstawowym jest brak możliwości ustawiania nagłówków, nie możemy dodać własnych ani modyfikować istniejących, bo przecież korzystamy z natywnego interfejsu HTML-a obiektów DOM i przeglądarki. Dodatkowo każde ładowanie danych jest zapytaniem typu ‘GET’ czyli wszystkie dane wysyłamy przy pomocy URL-a. No a gdzie sie podział POST? Na całe szczęscie istnieją obejścia umożliwiające wykonanie POST-a w świecie wielu domen ale o tym przy następnej okazji.

Dzięki!!!
Niestety, IE obsługuje zdarzenie onreadystatechange w nieco odmienny sposób. Rzeczywiście, teoretycznie istnieje wiele stanów readyState:
0 uninitialized
1 loading
2 loaded
3 interactive
4 complete
ale w praktyce funkcja script.onreadystatechange zwraca tylko ten ostatni – complete. Wtedy można dopiero usunąć wstrzyknięty (wykonany) kod w IE.
Powinno być zatem:
if(this.readyState==’complete’){
zamiast:
if(this.readyState==’loaded’){