Tetszik a bejegyzés? Iratkozz fel, oszd meg!


Cross-domain kommunikáció window.name alapon

Egyik projektemben két, nem azonos domainen levő oldal között kellett megoldanom a kommunikációt (egy oldal, és rajta egy iframe). Korábban írtam már egy lehetséges megoldásról, most úgy döntöttem, hogy egy még ismeretlen irányba megyek el, kipróbálva, hogy hogyan is működik a dolog a window.name segítségével.

A window JavaScript objektum name tulajdonságáról beszélünk, mely ezer éve jelen van minden böngészőben, bár csak mostanában sikerült felismerni, hogy ez bizony alkalmas különböző domainek közötti kommunikációra, adatcserére.

Mire jó a window.name?

Alapvetően az adott dokumentum “name” tulajdonsága egy azonosító tárolására szolgál, melynek (legfőképpen) akkor van szerepe, ha egy linknek a target tulajdonságát erre az aznosítóra állítjuk. Ezzel lehet egy linket egy másik frame-ben, iframe-ben megnyitni, vagy egy formot elküldeni.

<a href="http://barthazi.hu/" target="ajfrem"></a>
<iframe name="ajfrem" src="http://webakademia/hu/"></iframe>

Ebben a felállásban, ha a wekakademia.hu oldalon megnézzük a window.name értékét, akkor az “ajfrem” sztringet fogjuk visszakapni. Van azonban a window.name-nek van egy olyan tulajdonsága, mely semmilyen más értékre nem jellemző egy oldalon: böngészőnk bármely ablaka írni és olvasni tudja. Ez adott esetben egy komoly biztonsági rést is jelenthet, tehát csak óvatosan használjuk ezt ki!

Mire jó még a window.name?

Mielőtt nekikezdenénk az eltérő domainek közötti kommunikációnak, megosztok még egy trükköt, mely – főként webalkalmazásoknál, webszolgáltatásoknál – izgalmas lehet.

Amennyiben oldalunkra kívülről mutatnak linkek (akár “sima linkekről”, akár “akciót kiváltó linkekről” – például del.ici.us-nál egy új link hozzáadása – van szó), egy jellemző probléma lehet, hogy akár volt már korábban megnyitva egy ablak erről az oldal, akár nem, egy új ablak (fül) fog kinyílni, ezáltal egyre több ilyen alkalmazásunk lesz nyitva, ami nem mindig szerencsés.

Erre egy ugyan nem 100%-os, de jól működő megoldás lehet, ha az adott oldal betöltődésekor a window.name tulajdonságát valami egyedire (az oldal nevére) változtatjuk, a beágyazható kis badge-inket, egyéb bannereket, linkeket melyek az oldalra mutatnak, azokat pedig egy ugyanilyen értékű target tulajdonsággal látjuk el. Így a korábban már betöltött fülön fognak megnyilni ezek a linkek (vagy ha nem volt nyitva, akkor egy új fog nyílni).

Egy másik érdekes lehetőség a session kezelés, session adatok tárolása lehet, hiszen amikor új oldalt töltünk be az adott ablakba (fülre), akkor a window.name értéke nem változik. Csábító lehetőség, de igen óvatosan kell eljárnunk, hiszen adott esetben ezeket az értékeket bármilyen más oldal ki tudja olvasni. A linket már nem találom, de volt olyan trükk különben, hogy JavaScript kódokat cache-elt a window.name-ben valaki. Ezt hülyeségnek tartom. :)

Hogyan működik a window.name kereszdomaines kommunikáció?

A fentiek után gondolom mindenki érti a koncepciót: egyik dokumentum írja, a másik pedig olvassa a window.name tulajdonságot. A határait ugyan nem teszteltem, de elég nagy mennyiségű adathalmaz belefér, amire figyelnünk kell, hogy sztring alapú tulajdonságról beszélünk, tehát valamilyen módon szerializálnunk kell az átadandó objektumot, ha nem csak egy egyszerű sztringről van szó. Tömb szerű szerializációra kínál lehetőséget egy urlencode-olós megoldás, míg egy másik kiváló lehetőség a JSON használata lehet, mellyel komplex adatokat tudunk átpasszolni két domain között.

A bevezetőmben emlegetett location.hash alapú megoldással szemben, ahol a kommunikáció a weblap URL-jének # utáni részét manipulálva lehetséges, a window.name lehetővé teszi a kétirányú kommunikációt is – ami egy nagy előny lehet, ha megoldásokat keresünk.

A kivitelezés során a legkomolyabb kihívást az jelentette számomra, hogy valahogy hozzájussak a window objektumhoz. Egy oldal, és egy benne levő iframe megoldásnál két lehetőség van ugye, az egyik, hogy az oldal window.name-jén keresztül történik a kommunikáció, a másik pedig hogy az iframe-én keresztül. Ez utóbbi tűnik célszerűnek, tehát a kérdés, hogy hogyan lehet ezt az objektumot megtalálni.

Az érdekes válasz az az, hogy nincs rá szabványos (DOM) megoldás. A legjobb, működő megoldás a frames objektum használata (amivel utoljára akkor találkoztam, amikor még Netscape-re dolgoztam) lehet. Ennél számmal és a frame name tulajdonságával is hivatkozhatunk a frame-ekre, iframe-ekre, Safari alatt a névvel hivatkozás furcsán viselkedett, így szimplán így használtam:

var iframe = frames[0];
if (iframe && iframe.name) {...}

A kommunikáció igen bonyolult protokollját úgy oldottam meg, hogy az iframe betöltődését a name tulajdonságát folyamatos kiolvasással ellenőriztem, s ha egy “READY” jelent meg benne, akkor tudtam, hogy készen áll az iframe az adatok fogadására. Az iframe-ben is ráállítottam egy függvényt setInterval-lal a window.name figyelésére, s ha kapott egy üzenetet és feldolgozta azt, akkor az üzenet törlése után “READY” beállításával tudta visszajelezni, hogy készen áll a következő feladatra.

Alapvetően egész jól, látványosan használatónak tűnik a window.name, rossz tapasztalatom nem igazán volt vele.

Miért hackelünk?

A window.name alapú megoldás – bármilyen irányból nézzük is -, bizony hackelés. Felmerülhet a kérdés, hogy miért nem használunk más eszközt, valami olyat, ami szebben és jobban képes működni. A válasz az, hogy azért, mert ilyen eszköz nincs. A válasz kiegészítése, hogy viszont készül, sőt, egyes böngészőkben már most elérhető.

Éppen vonaton ülök viszonylag korlátos netezési lehetőségekkel, így hirtelen fejből nem emlékszem hogy mely böngészők implementálták már a lehetőséget, de az IE8 és még egy másik (Safari) böngésző rémlik fel szemeim előtt.

Viszont egy ideig ezek még nem lesznek elterjedt böngészők, így ha valamit ma kell megcsinálni úgy, hogy minél több böngészőben működjön, akkor nem tudjuk megoldani, csak hackeléssel – a window.name pedig minden elterjedt, a JavaScriptet értő böngészőben működik.

9 Hozzászólás - “Cross-domain kommunikáció window.name alapon”


  • Egy talán kicsit szofisztikáltabb megoldás lehetne flash local connection használata. Ahogy én tudom ezen keresztül tudnak a flashek egymással kommunikálni, external interface-en keresztül pedig tudnak JS-t hívni. Flash lefedettsége elég jó.

    Üdv,
    Felhő

  • Az erdekes az, hogy piszok nagy adatmennyiséget lehet tárolni a window.name-ben. Itt pl 2 Megát írnak: http://www.thomasfrank.se/sessionvars.html

  • Hodicska Gergely: Milyen szempontból lenne jobb megoldás? Miért hoznék be egy olyan technológiát, ami nincs meg minden böngészőben, és amihez nem értek (értsd: nincs fejlesztőkörnyezetem, nincs gyakorlatom)?

  • Jano: Igen, jellemzően simán belefér amit bele szeretnénk tenni.

  • Folyamatosan kiemeled, hogy azért ezzel csínján bánni, meg kvázi nem dokumentált feature, ráadásul valamilyen szinten ez egy nem kezelt security hole. Szóval sok szempontból bármikor megdőlhet egy újabb böngészőverzió esetén. Flash penetrációja nagyon magas, és ezzel a megoldással egy robosztusabb message bus-t lehet építeni.

    Üdv,
    Felhő

  • Hodicska Gergely: Szerintem dokumentált feature, és nem feltétlenül biztonsági rés csak azért, mert lehet vele veszélyeset alkotni. :) Nem hinném, hogy új böngészők ne támogatnák, ez a Flashről is elmondható ugyanúgy. Szóval miért is használjak egy olyan technológiát, amihez nem értek, és a gyakorlatban nagyon kicsit rosszabb a támogatottsága, mint az eddigi választásomnak?

  • Ha nem érted, akkor nyilván ne használd. :)

    Üdv,
    Felhő

  • Nekem nem nagyon akar működni. Nem tudom megváltoztatni a window.name-t

    Egy minimális kódot nem tudnál beilletszeni?

  • Joe, valoban nem is megy sajnos, csak ha ugyanazon a domainen van ket oldal. Illetve ha cross-domain szeretned megvalositani a kommunikaciot, akkor annak a felnek, amelyik eppen hozza akar ferni, meg kell valtoztatni egy rovid idore az adott frame URL-jet, es at kell allitani sajat domainre. Igy akkor hozzafer a masik altal beallitott window.name-hez, es modositani is tudja azt. Majd vissza tudja allitani az eredetire a cimet.

Te mit gondolsz?