Definicija
Cross Domain Data Request predstavlja specifičan zahtev za podacima, jer se podaci ne nalaze na domenu (protokolu ili portu) odakle potiče i sam zahtev.
Podrazumevano ponašanje servera je da ne dozvoljavaju pristup podacima sa drugih servera, a glavni razlog ove zabrane je mogućnosti da se vrše napredni zahtevi (POST, PUT i DELETE itd.) koji mogu dovesti do raznih bezbednosnih problema. Stoga su i AJAX zahtevi podrazumevano zabranjeni, a to ogranicenje je poznato pod nazivom “the same origin policy“ (srp. polisa zajedničkog porekla).
Medjutim neke vrste resursa ipak ne podležu ovoj zabrani, jer im pregledači podrazumevano dozvoljavaju pristup. Resurse koji se ne nalaze na domenu odakle potiče i sam zahtev je dozvoljeno pozvati jedino kroz “src” ili “href” atribute sledećih HTML elemenata: <script>, <img>, <video>, <iframe>.
Postoje rešenja i za zahteve kod kojih važi zabrana “the same origin policy“, ali to podrazumeva korišćenje specifičnih mehanizama. Upravo o tim mehanizmima je reč u ovom članku.
Prevazilaženje zabrane “the same origin policy”
a) Cross-Origin Resource Sharing (CORS)
Jedan od načina da se prevazidje zabrana “the same origin policy” je taj da server kome je poslat zahtev dozvoli Cross Domain DATA Request. U narednom delu je opisana komunikacija izmedju servera, a samim tim i postupak dobijanja dozvole za pristup podacima.
Cela komuikacija kreće od browser-a koji generiše i šalje zahtev. U zaglavlju zahteva postoji deo pod nazivom “Origin”. Ovo svojstvo definiše url adresu domena sa kojeg stiže zahtev:
1 |
Origin: http://www.webprogramiranje.org |
Ovaj podatak je bitan jer na osnovu nje server ima informaciju odakle dolazi poziv i da li ima pristup serveru. Praktično se cela komunikacija izmedju servera zasniva na razmeni specifičnih zaglavlja u zahtevima (eng. request header). Dozvola za pristup podacima sa drugog servera stiže u zglavlju odgovora kroz deo pod nazivom “Access-Control-Allow-Origin”. Ovo svojstvo može da sadrži dva tipa dozvole:
- Dozvola pristupa samo za specifični izvor (domen).
1Access-Control-Allow-Origin: http://www.webprogramiranje.org - Dozvola pristupa za sve izvore korišćenjem wildcard *.
Ova dozvola se koristi kod javnih resursa kojima mogu svi da pristupe npr. fontovi, biblioteke…).
1Access-Control-Allow-Origin: *
NAPOMENA
Ako se vrednosti u Access-Control-Allow-Origin ne poklapaju sa vrednosti Origin-a ili server ne odgovori sa ovim zaglavljem, pregledač obustavlja poziv i vraća grešku.
Primer
Ovde je prikazan deo serverskog koda koji omogućava svim izvorima pristup podacima korišćenjem wildcard *
1 2 3 |
<?php header('Content-type: text/html'); header('Access-Control-Allow-Origin: *'); |
NAPOMENA:
Ukoliko pri developmentu imate problema sa pristupanjem udaljenim serverima možete instalirati plugin za chrome pod nazivom “Moesif Origin & CORS Changer”. Ovaj plugin vam omogućava da šaljete “cross-domain requests” direktno iz browsera bez “Cross Origin Errors”.
b) JSONP
JSONP je drugi način da se dobiju podaci sa servera koji nije isti kao server odakle potiče zahtev. Ovaj mehanizam se zasniva na činjenici da je pristup eksternom serveru dozvoljen kroz “src” atribut <script> taga. Objašnjenje JSONP koncepta je najlakše kroz primere koda, pa ćemo početi od jednostavnog koda koji se sastoji iz dva script taga. U prvom delu se nalazi funkcija dataHandler() koja štampa ono što joj se prosledi kroz parametar, dok u drugom delu pozivamo dataHandler()
1 2 3 4 5 6 7 8 9 10 11 |
// Callback Funkcija koja prihvata neki JSON kao parametar i štampa ga <script type="text/javascript"> function dataHandler (data){ console.log(data); } </script> // Pozivanje callback funkcije sa JSON objektom kao parametrom <script type="text/javascript"> dataHandler({"title":"Webprogramiranje skripte","description":"Strava sajt o web programiranju :)}); </script> |
Uvek postoji mogućnost da deo sa pozivanjem funcije izvučemo u odvojeni fajl npr. datahandler.js pa ga naknadno ubacimo kroz link.
1 |
dataHandler({"title":"Webprogramiranje skripte","description":"Strava sajt o web programiranju :)}); |
Da bi ovaj fajl bio dostupan potrebno ubacimo link do tog fajla u src atribut. Pošto je dozvoljeno da se kroz “src” atribut poziva fajl i sa nekog drugog servera, taj link praktično postaje REST endpoint.
1 2 3 4 5 6 7 8 9 |
// Callback Funkcija koja prihvata neki JSON kao parametar i štampa ga <script type="text/javascript"> function dataHandler (data){ console.log(data); } </script> // Pozivanje callback funkcije sa JSON objektom kao parametrom <script src="linkdoFajlaKojiPozivaDataHandlerFunkciju" type="text/javascript"></script> |
Ako ceo script tag koji poziva funkciju sa JSON parametrom generišemo dinamičiki, onda bi kod ovako izgledao:
1 2 3 4 5 6 7 8 9 |
<script type="text/javascript"> function dataHandler (data){ console.log(data); } </script> var script = document.createElement('script'); script.src = 'https://linkdoFajlaKojiPozivaDataHandlerFunkciju'; document.body.appendChild(script); |
Zatim u src atributu možemo da definišemo koja je callback funkcija zadužena za ovaj fajl, tako što u nastavku linka prosledimo ?callback=”dataHandler”:
1 2 3 4 5 6 7 8 9 |
<script type="text/javascript"> function dataHandler (data){ console.log(data); } </script> var script = document.createElement('script'); script.src = 'https://linkdoFajlaKojiPozivaDataHandlerFunkciju?callback="dataHandler'; document.body.appendChild(script); |
Iz prethodnog zaključujemo da je potrebno JSON objekat staviti da bude parametar neke callback funkcije. Za ovo potrebu možemo da koristimo online servis https://json2jsonp.com koji prebacuje JSON objekat u funkciju čiji parametar je taj JSON objekat.
Primer
U ovome primeru želimo da “dohvatimo” JSON objekat sa url adrese čiji domen nije isti kao domen odakle šaljemo AJAX zahtev. Za potrebe ovog primera JSON objekat je generisan koristeći online resurs myjson.com. REST API endpoint koji dobijamo preko ovog online servisa je: “https://api.myjson.com/bins/amz5t”. Medjutim ova se adresa ne nalazi na istom domenu sa koga ćemo da pošaljemo zahtev. Stoga je potrebno da koristimo JSONP mehanizam.
To podrazumeva da ovaj JSON objekat predstavimo kao parametar neke callback funkcije. Za prebacivanje JSON objekta u parametra funkcije koristimo sledeći online servis: “https://json2jsonp.com”. Ovaj servis nakon obrade našeg JSON objekta generiše URL adresu: “https://json2jsonp.com/?url=https://api.myjson.com/bins/amz5t&callback=dataHandler”. Sada kada imamo sve neophodne podatke, deo vezan za JSONP mehanizam bi izgledao ovako:
1 2 3 4 |
/* Generisanje script tag-a čiji je source JSON u vidu atributa funkcije */ var script = document.createElement('script'); script.src = 'https://json2jsonp.com/?url=https://api.myjson.com/bins/amz5t&callback=dataHandler'; document.body.appendChild(script); |
A ceo kod primera možete da vidite ovde:
See the Pen JSONP by Web programiranje (@chos) on CodePen.