Cross-domain kérések a háttérben JSONP segítségével
Manapság az egyre összetettebb weboldalak, webalkalmazások fejlesztésekor gyakran merül fel az igény, hogy kérést küldjünk a háttérben egy másik domainre, aldomainre. Eme próbálkozásainkat a böngészők (biztonsági okokra hivatkozva) nem nagyon díjazzák, de szerencsére van egy lehetőségünk a kivitelezésre, a JSONP, erről fogunk most beszélni.
A probléma: same origin domain policy
A Netscape Navigator 2.0 óta létezik egy same origin domain policy nevű koncepció, melynek értelmében a böngésző oldali programozási nyelvek nem érhetnek el más domaineken lévő erőforrásokat. Az alábbi táblázat tartalmazza, hogy ennek értelmében mit lehet és mit nem. Legyen a kiindulási URL-ünk a http://xy.hu/index.php
, ennek az oldalnak a JavaScript kódjából próbálunk meg most (elméletben) kéréseket küldeni a következő URL-ekre:
URL | Magyarázat | Eredmény |
---|---|---|
http://xy.hu/test.php | Ugyanaz a hoszt és port | Sikeres |
http://xy.hu/dir/test.php | Ugyanaz a hoszt és port | Sikeres |
http://xy.hu:3000/test.php | Ugyanaz a hoszt, másik port | Sikertelen |
https://xy.hu/test.php | Másik protokoll | Sikertelen |
http://www.xy.hu/test.php | Másik hoszt | Sikertelen |
Ebből láthatjuk, hogy böngészők csak az ugyanarra a domainre, ugyanazzal a protokollal és ugyanarra a portra küldött kéréseket támogatják. Kivételt jelent ez alól a HTML <script>
elem, a JSONP ezt használja ki.
A megoldás: JSONP
Elmélet
A JSONP jelentése „JSON with Padding”. Nagyon egyszerű, mégis nagyon hasznos technika, a lényege, hogy írunk egy callback függvényt, majd a JavaScript kódunkból dinamikusan beszúrunk egy script taget, amely egy másik szerveren helyet foglaló JavaScriptre fog hivatkozni. A másik szerveren valójában egy valamilyen szerveroldali programozási nyelvben írt program várakozik, amelynek a kimenete egy egyszerű JavaScript függvényhívás (a callback függvényünké) lesz, a paraméterében egy JSON sztringgel, amely a továbbítandó adatokat tartalmazza. Így a végén a callback függvényünk paraméterében megkapjuk a kívánt adato(ka)t. Szeretném itt megjegyezni, hogy bár a kérés a háttérben történik, akár az AJAX kérések esetében, de a kettőnek nem sok köze van egymáshoz, tehát a JSONP nem AJAX. A későbbiekben láthatjuk, hogy sokkal nehezebb felügyelni, kontrollálni mint egy AJAX kérést. Most pedig lássuk működés közben.
Gyakorlat
Tegyük fel, hogy van egy oldalunk amely a http://xy.hu/index.php
URL-en érhető el. Innen szeretnénk egy kérést indítani JavaScriptből a http://example.com/test.php
irányába. Először is definiáljuk a callback függvényünket, a neve legyen parseRequest()
:
function parseRequest(response) {
console.log(response);
}
Ez annyit csinál most, hogy a kapott response
paramétert kiírja a konzolra. A következő lépés a script tagünk beillesztése, amely a http://example.com/test.php
-re mutat:
var url = "http://example.com/test.php?callback=parseRequest";
var script = document.createElement("script");
script.setAttribute("src", url);
document.getElementsByTagName("head")[0].appendChild(script);
Látható, hogy átadjuk a callback paraméterben a callback függvényünk nevét, erre a függvényhívás miatt lesz szükségünk. Végül a http://example.com/test.php
címen lévő PHP szkriptünk:
<?php
$callback = $_GET['callback'];
echo $callback . '({"data": "Hello"});'; // parseRequest({"data": "Hello"});
Ennek a kimenete egy JavaScript kód lesz, amely meghívja a parseRequest()
nevezetű függvényünket, a paraméterében átadva neki a kívánt adatokat, természetesen JSON-ban.
Korlátok
Korábban említettem, hogy a JSONP nem AJAX, tulajdonképpen egy szimpla kérés a szerver felé. Ebből fakadóan van több korlátja is, többek között, hogy nem tudjuk a kérést megszakítani, nem kapunk értesítést az aktuális állapotáról, és az időtúllépések kezelése is sokkal nehezebb. Ez főleg akkor okozhat gondot, ha long polling technikával szeretnénk kombinálni, érdemes ilyenkor úgy megírni a szerveroldali alkalmazásunkat, hogy a timeout felé közeledve a szerver küldjön valamilyen adatot, ezzel lezárva a kapcsolatot, mert a timeoutról már nem fogunk értesülni kliens oldalon, mint például AJAX esetében. További hátránya, hogy POST
kérések küldésére nem alkalmas, így főleg olyan célokra ideális, ahol adatot kérünk le a szervertől, például support chat, valósidejű statisztikai alkalmazások stb.
Biztonság
Az egyik legnagyobb hátulütője a JSONP-nek a biztonság. Fontos tisztáznunk, hogy mennyire bízunk meg abban a domainben, amelyre a kérést küldjük, hiszen más JavaScript kódot is beinjektálhatnak az oldalunkba, ezzel pedig teljes hozzáférést nyerhetnek, átszabhatják azt, cookie-t lophatnak, átirányíthatják a felhasználót egy másik oldalra, vagy pedig bejelentkezett felhasználóktól lophatnak érzékeny adatokat. Vigyázni kell tehát, hogy minden harmadik féltől származó adatot az ördögtől valóként kezeljünk, és végezzük el a megfelelő ellenőrzéseket, mielőtt felhasználnánk azt.
■kacsandiz
Kacsándi Zsolt fő érdeklődési területei a webalkalmazások fejlesztése, fejlesztési folyamatok hatékonyságának növelése és a minőségbiztosítás. A fejlesztés mellett igyekszik képben lenni az üzemeltetéssel kapcsolatos kérdésekben, technológiákban is.Szabadidejében szívesen publikál szakmai témákban, illetve segédkezik rendezvények szervezésében.
A modern böngészők már
+1, már évek óta van
Így van, viszont nekem egy
Itt van egy táblázat a CORS támogatottságáról: http://caniuse.com/cors
Feltételezem, hogy a Google is azért használja ezt az Analytics-nél, hogy a régebbi böngészőket ne zárja ki a statisztikákból.
Hjah, 55%-nál van support
85%-nál (a mobilokat nem
nem tud sütiket küldeni CORS
Én ennek azért örülök. Utálom, ha minden harmadik fél mindenféle hulladékkal látja el a HTTP kéréseket. Ha már CORS, akkor az legyen szép tiszta HTTP mindenfajta sütimorzsa nélkül. Ma már szinte minden szolgáltatás tud valami kulcs alapú egyeztetést. Azaz egyszer autentikál, kap egy kulcsot, és azután azt hozzárakod mindig az URL-hez. Legalább, ha nem akarom, akkor a Facebook szerű szörny nem követ a világ végére is.
Egyrészt harmadik fél soha
IE 8-9-nek nulla a CORS
Nem is emlékszem erre a cikkre, újra el fogom olvasni.
Az Analytics nem ezt
Milyen képekről van szó? :D
Képek
Valahol a kód közepén van, hogy:
Ilyen van az egyik oldalon,
Ez magát a GA javascript
Egyébként tényleg régi, mostanában már DOM manipulációt használnak, mert az nem blokkol töltődés közben.
Urchin
var
sc.type='text/javascript';
sc.id="_gasojs";
sc.src='https://'+d+'/analytics/reporting/overlay_js?gaso='+_utk+'&'+Math.random();
document.getElementsByTagName('head')[0].appendChild(sc);
Ez pedig a kód végén van. :)
Szerk.: T.G 15.55-ös hozzászólására akart válasz lenni.
Ez meg a site overlay,
Az Errorception blogján most