A JSONP vagy a „JSON kitöltéssel” az alap JSON-formátum kiegészítése . Lehetőséget biztosít adatok lekérésére egy másik tartományban található szerverről, amely művelet a tipikus webböngészőkben tiltott a tartománykorlátozási szabályzat miatt .
2005 júliusában George Jempty azt javasolta, hogy a JSON elé kerüljön egy opcionális változódeklaráció. [1] [2] Az eredeti JSONP-javaslatot, ahol a kitöltés egy visszahívási funkció, valószínűleg Bob Ippolito készítette 2005 decemberében [3] , és ma már számos Web 2.0 alkalmazás használja, mint például a Dojo Toolkit , a Google Web Toolkit , [4] és Web Services .
A tartománykorlátozási házirend szerint egy szerveren található weboldalexample1.com nem kapcsolódhat más szerverhez, mint a example2.com. A JSONP technológia azon a tényen alapul, hogy a böngésző biztonsági szabályzata nem tiltja HTML-elemek <script type="text/javascript" src="…"/> használatát az oldal betöltésének kiszolgálójától eltérő szerverekhez. A Open Policy on Elements <script>használatával egyes oldalak arra használják őket, hogy olyan JavaScript-kódot töltsenek be, amely más forrásokból származó, dinamikusan generált JSON-adatokon működik. A JSONP-kérelmek nem JSON-t, hanem tetszőleges JavaScript-kódot kapnak. Ezeket a JavaScript értelmező dolgozza fel, nem a JSON-elemző. A JSONP használata komoly biztonsági kockázatokkal jár, a legtöbb esetben a CORS használata a legjobb választás.
A minta sémája leírható egy adott URL -re küldött kéréssel, amely JSON-adatokat ad vissza. Egy JavaScript program kérheti ezt az URL-t, például az XMLHttpRequest segítségével . Tegyük fel, hogy a Foo objektum UserId-je 1234. Az 1234-es azonosítót átadó URL-t kérő böngészőhttp://server2.example.com/Users/1234 a következő formátumban kap választ:
{ "Név" : "Foo" , "Id" : 1234 , "Ranghely" : 7 }A harmadik fél válaszában lévő JSON-adatok általában dinamikusan jönnek létre az URL-ben átadott kérési paraméterek alapján.
A következő HTML-elem <script>attribútumként határoz meg egy srchivatkozást, amely JSON-t ad vissza:
< script type = "application/javascript" src = "http://server2.example.com/Users/1234" > </ script >A böngésző viszont letölti a fájlt , elemzi a tartalmát, blokkkéntscript értelmezi a nyers JSON-adatokat , és szintaktikai hibát dob. Még ha az adatokat JavaScript objektumliterálként értelmezték is, nem érhetők el a böngészőben futó JavaScriptből, mert az objektumliterálok nem érhetők el változóhoz rendelés nélkül.
A JSONP-mintában a címke <script>src attribútuma által mutatott URL függvényhívásba csomagolt JSON-adatokat ad vissza. Ilyen esetben a JavaScript-környezetben már definiált függvény manipulálhatja a JSON-adatokat. A JSONP-kitöltés így nézhet ki:
functionCall ({ "Név" : "Foo" , "Id" : 1234 , "Rank" : 7 });A függvényhívás a "P" a JSONP szóban - "padding" (töltelék, " indent ") a tiszta JSON körül, vagy egyes források szerint [5] - "előtag". Megállapodás szerint a böngésző a visszahívási függvény nevét elnevezett kérési paraméterként, általában a név jsonpvagy callbacka kérésben szereplő név használatával továbbítja a szervernek, azaz
< script type = "text/javascript" src = "http://server2.example.com/Users/1234?jsonp=parseResponse" > </ script >Ebben a példában a töltelék a következő lesz:
parseResponse ({ "Név" : "Foo" , "Id" : 1234 , "Ranghely" : 7 });Míg a kitöltés (előtag) általában egy visszahívási függvény neve, amely a böngészőben a végrehajtási kontextusban van definiálva. A függvény neve mellett az előtag jelenthet változónevet, operátort ifvagy bármely más JavaScript-operátort. A JSONP-kérésre adott válasz (szigorúan véve a JSONP-mintának megfelelő kérés) nem JSON-objektum, és a böngésző nem kezeli ilyenként. A „töltelék” bármilyen JavaScript-kifejezés lehet, és nem szükséges, hogy a JSON benne legyen. De ez általában egy JavaScript-darab, amely függvényhívást alkalmaz bizonyos JSON-adatokra.
Más szavakkal, a JSONP tipikus használata tartományok közötti hozzáférést biztosít egy meglévő JSON API -hoz azáltal, hogy a JSON-kitöltést egy függvényhívásba csomagolja.
A JSONP-nek csak akkor van értelme, ha szkriptelemmel együtt használják. Minden új JSONP-kéréshez a böngészőnek új elemet kell hozzáadnia, <script>vagy egy meglévőt kell használnia. Az első manipuláció, egy új szkriptelem hozzáadása, dinamikus DOM-manipulációval történik, és az úgynevezett szkriptelem-injektálás . Az elem <script>beszúrásra kerül a HTML DOM-ba, a kívánt JSONP-végpont URL-címével az „src” attribútumban.
Ezt a dinamikus szkriptelem-injektálást általában egy javascript segédkönyvtár végzi. A jQuery és más keretrendszerek segédfunkciókkal rendelkeznek a JSONP számára; külön megoldások is vannak [6] [7] .
A JSONP-hívásokhoz dinamikusan beillesztett szkriptelem így néz ki:
< script type = "text/javascript" src = "http://server2.example.com/Users/1234?jsonp=parseResponse" > </ script >Az elem beillesztése után a böngésző feldolgozza azt, és HTTP GET-et hajt végre az src URL-címen, lekérve a tartalmat. A böngésző ezután JavaScriptként kezeli a visszaadott terhelést. Általában ez egy függvény végrehajtása.
Ebben az értelemben a JSONP használata úgy írható le, mint amely lehetővé teszi a böngészőoldalak számára, hogy megkerüljék a tartománykorlátozási házirendet egy szkriptelem beszúrásával.
A más szerverekről származó szkriptcímkék bevonása lehetővé teszi a távoli szerverek számára, hogy bármilyen tartalmat keverjenek a webhelyen . Ha a távoli kiszolgálókon olyan biztonsági rések vannak, amelyek lehetővé teszik a JavaScript keverését, az eredeti szerver által biztosított oldal fokozott kockázatnak van kitéve.
Jelenleg folynak a lépések a JSON-P [8] biztonságosabb, szigorúbb részhalmazának meghatározására, amelyet a böngészők kényszeríthetnek arra, hogy egy adott MIME-típusú szkriptet kérjenek, például "application/json-p". Ha a válasz nincs szigorú JSON-P-ként értelmezve, a böngésző hibát jelezhet, vagy egyszerűen figyelmen kívül hagyja a teljes választ. Jelenleg azonban a JSONP egyetlen érvényes MIME-típusa az „application/javascript” [9] .
A primitív JSONP gazdagépek érzékenyek a helyek közötti kérés-hamisításra (CSRF vagy XSRF) [10] . Mivel a HTML-címkére <script>nem vonatkozik a tartománykorlátozási szabályzat a valós böngészőmegvalósításokban, egy rosszindulatú oldal kérhet és fogadhat egy másik webhelyhez tartozó JSON-adatokat. Ez lehetővé teszi, hogy a JSON-adatokat rosszindulatú oldallal összefüggésben feldolgozzák, és esetleg jelszavakat vagy más érzékeny adatokat fedjenek fel, ha a felhasználó egy másik webhelyre van bejelentkezve.
Ez csak akkor okoz problémákat, ha a JSON-kódolású adatok érzékeny információkat tartalmaznak, amelyeket nem szabad harmadik félnek felfedni, és a szerver a böngésző tartománykorlátozási házirendjére támaszkodik, hogy blokkolja az adatátvitelt rossz kérés esetén. A probléma nem áll fenn, ha a szerver maga határozza meg a kérés megfelelőségét, és csak akkor ad át adatokat, ha a kérés érvényes. A sütik önmagukban nem alkalmasak a kérés jogosságának meghatározására. A cookie-k használata önmagában is ki van téve a webhelyek közötti kérés-hamisításnak .
JSONPP ( eng. paraméteres JSON padding - "parameterized JSON with padding") - a JSONP ötlet fejlesztése.
A JSONPP tartalmazza a forrás URL-t, a JSON-adatokat feldolgozó függvény nevét, az adatok beérkezése utáni eval karakterláncot és az adatok befejezésekor értékelendő karakterláncot:
JSON_call ( SRC , JSONP , JSONPP , ONLOAD );végül megfordul
ans = JSONP ( SRC ) { eval ( JSONPP ( ans )); eval ( ONLOAD ); }Általában a paraméterek száma nem fontos magának a JSONPP-ötletnek. SRC, JSONP, JSONPP (és ezek feldolgozása a szerver oldalon, majd a kliens oldalon) elég ahhoz, hogy JSONPP legyen. Tekintsük az S3DB szolgáltatással való munka példáját.
function s3db_jsonpp_call ( src , next_eval ){ var call = "call_" + Math . véletlenszerű (). toString (). csere ( /\./g , "" ); var headID = dokumentum . getElementsByTagName ( "fej" )[ 0 ]; var script = dokumentum . createElement ( 'script' ); forgatókönyv . id = hívás ; forgatókönyv . type = 'text/javascript' ; // párnázott, paraméterezett json használatával src = src + "&format=json&jsonp=s3db_jsonpp&jsonpp=" + next_eval + "&onload=remove_element_by_id('" + script . id + "')" ; forgatókönyv . src = src ; fejazonosító . appendChild ( script ); // válasz lekérése } function s3db_jsonpp ( ans , jsonpp ){ eval ( jsonpp ); return ans ; } function remove_element_by_id ( id ){ var e = document . getElementById ( id ); e . szülőcsomópont . RemoveChild ( e ); return false ; }A példában a függvény s3db_jsonpp_call()létrehoz egy szkriptelemet a DOM fejrészében, amelynek src-je megegyezik a JSONPP-hívással.
Miután megkapta a választ a kiszolgálótól, meg lesz hívva s3db_jsonpp() - a hívási paraméterekben átadásra kerül, ahogyan a JSONP szabályok szerint kell.
Belsőleg s3db_jsonpp()működni fog eval(jsonpp), és az ans értékét visszaadjuk.
A hívás a létrehozott szkript azonosítójával a fejben eval(onload)a végrehajtáshoz vezet, remove_element_by_id()és ennek eredményeként annak törléséhez, mert úgysem kerül felhasználásra, mivel a példában szereplő id véletlenszerűen generált a függvény legelején s3db_jsonpp_call(). Ez a hívás a szerver válaszában van.