Ajax - XMLHttpRequest
V predchádzajúcom dieli bolo vymenovaných niekoľko možných spôsobov komunikácie medzi klientom a serverom. Dnes sa zameriame na jeden z nich a ukážeme si, ako odosielať požiadavky a spracovať odpovede prostredníctvom objektu XMLHttpRequest.
Spôsobov, ako implementovať komunikáciu klienta so serverom je viac, avšak použitie objektu XMLHttpRequest
sa s technikou Ajax spája asi najčastejšie. Použitie tohto objektu je v podstate jediné čisté riešenie komunikácie, pri ktorom sa technológia používa presne na to, na čo bola určená. XMLHttpRequest
umožňuje vytvárať požiadavky s použitím rôznych metód, vrátane metód GET a POST. V dnešnej dobe ho podporujú všetky súčasné prehliadače.
Objekt XMLHttpRequest
umožňuje prenášať údaje vo formáte XML, vďaka čomu môžeme na strane klienta jednoduchšie spracovávať prijaté údaje. Rovnako je však možné prenášať čistý text, čo sa hodí v prípadoch, v ktorých by bol XML formát kanónom na vrabce. Hoci je XMLHttpRequest
určený na komunikáciu klienta so serverom, nie vždy je to tá najlepšia voľba. Nedostatkom objektu XMLHttpRequest
je, že v prehliadači Internet Explorer je možné tento objekt vytvoriť iba s použitím technológie ActiveX. To môže byť problémom, pretože pri vyššom stupni zabezpečenia sa pri vytváraní tohto objektu môže používateľovi zobraziť otravná hláška, prípadne sa nemusí objekt XMLHttpRequest
vôbec vytvoriť. V prehliadači Internet Explorer 7 už toto obmedzenie neplatí a objekt XMLHttpRequest
sa dá vytvoriť rovnakým spôsobom ako v ostatných prehliadačoch.
Ďalšou vlastnosťou komunikácie prostredníctvom objektu XMLHttpRequest
je, že nie je možné komunikovať so serverom z inej domény, než z ktorej bol spustený skript. Toto obmedzenie sa dá obísť nastavením prehliadača, ale z bezpečnostného hľadiska to nie je príliš rozumné. Ak by totiž bola povolená komunikácia so servermi z inej domény, bolo by jednoduché okrem iného napríklad hlasovať za nejakú možnosť v ľubovoľnej ankete, prípadne z Vašej IP adresy vložiť príspevok do nejakej diskusie na inej stránke. Pre komunikáciu so servermi z inej domény je preto lepšie vytvoriť na serveri proxy stránku, ktorá takúto komunikáciu zabezpečí.
Vytvorenie objektu XMLHttpRequest
Pri vytváraní objektu XMLHttpRequest
sa postupne skúšajú viaceré spôsoby. Uprednostňuje sa vytvorenie objektu XMLHttpRequest
jeho konštruktorom, ako keby to bol objekt ako každý iný. Až v prípade, že konštruktor nie je k dispozícii, príde na rad vytvorenie tohto objektu pomocou technológie ActiveX. V mnohých ukážkach na webe bolo toto poradie opačné a v podstate na ňom do istej doby ani nezáležalo. Ak bola k dispozícii technológia ActiveX, vytvoril sa XMLHttpRequest
pomocou nej a až keď sa to nepodarilo, použil sa konštruktor pre XMLHttpRequest
. Príchodom prehliadača Internet Explorer 7 už na poradí záleží, pretože ten umožňuje vytvoriť XMLHttpRequest
obidvomi spôsobmi, pričom chceme uprednostniť natívny objekt XMLHttpRequest
.
function createXhr ()
{
var xhr = null;
if (window.XMLHttpRequest)
xhr = new XMLHttpRequest ();
else if (window.ActiveXObject)
try { xhr = new ActiveXObject ("Msxml2.XMLHTTP"); }
catch (e)
{
try { xhr = new ActiveXObject ("Microsoft.XMLHTTP"); }
catch (e) {}
}
return xhr;
}
Možno sa pýtate, prečo sa pokúšame vytvoriť ActiveX objekt Msxml2.XMLHTTP
a pri neúspechu vyskúšame ActiveX objekt Microsoft.XMLHTTP
. Je to tým, že objekt XMLHttpRequest
má viacero implementácií. Pomocou objektu Microsoft.XMLHTTP
bolo možné vytvoriť objekt na komunikáciu so serverom dávno pred tým, než sa objavil objekt XMLHttpRequest
v iných prehliadačoch. Neskôr vznikla ďalšia verzia tohto objektu Msxml2.XMLHTTP
, ktorá sa líši snáď iba pomenovaním.
Vytvorený objekt XMLHttpRequest
poskytuje niekoľko metód:
- abort ()
- Ukončí požiadavku.
- getAllResponseHeaders ()
- Vráti v reťazci zoznam všetkých hlavičiek.
- open ("metóda", "url"[, asyncFlag[, "userName"[, "password"]]])
- Priradí požiadavke cieľovú URL, metódu a ďalšie voliteľné parametre.
- send (content)
- Odošle požiadavku so zadaným obsahom.
- setRequestHeader ("label", "value")
- Pridá k požiadavke hlavičku.
Vlastnosti objektu XMLHttpRequest:
- onreadystatechange
- Funkcia pre obsluhu udalosti zmeny stavu objektu.
- readyState
- Číslo reprezentujúce aktuálny stav objektu: 0 = nenainicializovaný (uninitialized), 1 = nahráva (loading), 2 = nahraný (loaded), 3 = interaktívny (interactive), 4 = dokončený (complete)
- responseText
- Reťazec s údajmi, ktoré poslal server.
- responseXML
- XML (DOM-kompatibilný objekt) s údajmi, ktoré poslal server.
- status
- Návratový kód odpovede, ako napr. 404 pre nenájdenú stránku alebo 200 pre úspech.
- statusText
- Text, ktorý dopĺňa návratový kód odpovede.
Odoslanie požiadavky
Z predchádzajúceho výpisu metód objektu XMLHttpRequest
vidíme, že pri otváraní novej požiadavky môžeme nastaviť, či má byť volanie synchrónne alebo asynchrónne. Predvolená hodnota je true
, takže bez uvedenia tretieho argumentu metódy open
bude volanie asynchrónne. Ak by sme nastavili tretí argument na false
, volanie by bolo synchrónne. To by znamenalo, že hneď po zavolaní metódy send
by sme mohli pracovať s odpoveďou, ku ktorej by sme sa dostali prostredníctvom vlastností responseText
alebo responseXML
. Avšak pri synchrónnom volaní musí klient na odpoveď čakať a počas tohto čakania nemôže nič robiť. Preto je vždy lepšie použiť asynchrónne volanie (okrem veľmi výnimočných prípadov).
Odoslanie požiadavky metódou POST
Najčastejšie sa používajú metódy open
a send
. Odoslanie požiadavky metódou POST by vyzeralo nasledovne:
function sendRequest (data, url)
{
var xhr = createXhr ();
if (xhr)
{
xhr.open ("POST", url);
xhr.onreadystatechange = function () { if (receiveResponse (xhr)) xhr = null; };
xhr.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded");
xhr.send (data);
}
return xhr;
}
Pri asynchrónnom volaní nastavíme obslužnú funkciu udalosti readystatechange
, ktorá sa potom zavolá pri každej zmene stavu požiadavky. Tu by som chcel upozorniť na funkciu, ktorú sme v príklade použili ako obslužnú. Táto funkcia volá ďalšiu funkciu receiveResponse
, ktorej v argumente posunieme objekt xhr
. Dôležité je to, že po spracovaní odpovede, keď už viac nebude potrebné pristupovať k objektu xhr
, vráti funkcia receiveResponse
hodnotu true
, aby bolo možné uvoľniť objekt xhr
z pamäte. V mnohých ukážkach na webe takéto uvoľňovanie pamäte chýba, čo má za následok v niektorých prehliadačoch to, že pri každej požiadavke na server sa obsadí ďalší kus pamäte. Konkrétne ide o tzv. memory leaks v prehliadači Internet Explorer. Táto pamäť sa dá potom uvoľniť jedine reštartom prehliadača.
Pri požiadavkách odosielaných metódou POST musíme ešte nastaviť hlavičku požiadavky Content-Type
na application/x-www-form-urlencoded
, aby server vedel, že obsahom je zakódovaný formulár.
Odoslanie požiadavky metódou GET
Odoslanie požiadavky metódou GET je veľmi podobné, ale o niečo jednoduchšie. Keďže odosielané údaje sú zakódované už priamo v URL, netreba ich v metóde send nastavovať. Podobne netreba nastavovať hlavičku:
function sendRequest (data, url)
{
var xhr = createXhr ();
if (xhr)
{
xhr.open ("GET", url);
xhr.onreadystatechange = function () { if (receiveResponse (xhr)) xhr = null; };
xhr.send (null);
}
return xhr;
}
Nasledujúcim krokom bude prijatie a spracovanie odpovede nastavenou metódou receiveResponse
.
Prijatie odpovede
Pri vytváraní požiadavky sme priradili objektu XMLHttpRequest
obslužnú funkciu, ktorá sa volá pri výskyte udalosti readystatechange
. Úlohou tejto obslužnej funkcie je spracovať prijatú odpoveď, prípadne ohlásiť chybu. Môže vyzerať nasledovne:
function receiveResponse (xhr)
{
if (xhr.readyState == 4)
{
if (!xhr.status || xhr.status == 200)
alert (xhr.responseText);
else
alert ("Error: " + xhr.statusText);
return true;
}
return false;
}
Pri prijatí odpovede sa v prvom rade skontroluje vlastnosť readyState
. Tá obsahuje kód stavu, v akom sa požiadavka nachádza. V drvivej väčšine prípadov chceme obslúžiť stav s kódom 4, kedy sa dokončilo prijatie odpovede. V komunikácii cez protokol HTTP má každá odpoveď svoj stav, ktorý je vyjadrený číslom vo vlastnosti status. Ak prišla odpoveď v poriadku, bude jej stav označený číslom 200. Iný stav znamená, že pravdepodobne nastala nejaká chyba. Ak spúšťame skript z lokálneho počítača bez použitia webového servera, môžeme pristupovať priamo k súborom na disku. Keďže v takomto prípade nekomunikujeme s webovým serverom, nemusí byť stav odpovede nastavený.
Táto funkcia vráti true
v prípade, že požiadavku spracovala a objekt xhr
nebude už viac potrebovať. V opačnom prípade vráti false
. Ako bolo skôr spomenuté, takéto správanie sme si definovali kvôli správnemu uvoľňovaniu pamäte.
Záver
V tejto časti seriálu sme si ukázali základy práce s objektom XMLHttpRequest
, ktoré by mali stačiť na vytvorenie jednoduchej komunikácie klienta so serverom. V ďalšej časti si ukážeme, ako by sa dala realizovať ekvivalentná komunikácia prostredníctvom skrytého rámca.
Čím sa líši táto ukážka od ostatných príkladov komunikácie klienta so serverom dostupných na Internete je hlavne to, že sa staráme aj o uvoľňovanie pamäte. Keď nepoužívame takúto komunikáciu intenzívne, nemusíme sa o neuvoľnenú pamäť príliš starať. Pri častej komunikácii však bez uvoľňovania pamäte hrozí kolaps aplikácie, webového prehliadača, prípadne celého systému z dôvodu vyčerpania systémových zdrojov.