Metody komunikace v HTML5

Čtenáři Zdrojáku určitě vědí, že rodina technologií HTML5 nabízí mnohem víc než jen tagy a značkování. Součástí těchto nových technologií je také velké množství JavaScriptových API a v něm i řada nových metod, které umožňují komunikaci mezi klientem a serverem nebo mezi dokumenty. V článku si tyto metody ukážeme.

Tento článek obsahuje přehled technologií, informace o jejich dostupnosti v prohlížečích a (tam, kde je to možné) ukázkové příklady. Společně se podíváme na tyto technologie:

  • XHR a XHR2 s CORS
  • Web Messaging
  • Web Sockets
  • Server-Sent Events
  • Web Workers

Předtím, než se podíváme na jednotlivé API, si ukážeme základní komunikační model, který používá více zde popisovaných rozhraní.

Tento článek byl napsán Remy Sharpem. Remy (na Twitteru známý jako @rem) je zakladatel projektů jQuery for Designers a Full Frontal JavaScript conference, dále je vývojář a blogger. Stručně řečeno – Remi je stejný blázen do JavaScriptu, HTML & CSS jako veverka do svých oříšků během zimních měsíců. Originál Methods of Communication vyšel na serveru HTML5 Doctor pod licencí CC-BY-NC.

Společný komunikační model

Všechny funkce obsluhující události (event handlers) přijímají objekt event, který obsahuje atribut data (s výjimkou XHR). Ten obsahuje data, která jsou součástí odeslané zprávy.

Události (opět s výjimkou XHR) většinou využívají metod onmessage a postMessage, případně send. Například:

    // kód příjemce
    recipient.onmessage = function (event) {
    console.log('received message: ' + event.data);
    };

    // kód na straně odesílatele
    recipient.postMessage('hi there'); // nebo recipient.send('hi there');

Toto je běžný způsob, který ale není úplně stejný ve všech technologiích. Dvě nejdůležitější části jsou ale společné:

  • metody k odesílání dat ( postMessage nebo send), a
  • obsluha událostí, která čeká na událost message a přijímá objekt event (ten obsahuje atribut  data).

Také je důležité zmínit, že většina prohlížečů umožňuje pouze odesílání řetězců, takže je nutné pro jakákoliv jiná data použít JSON stringifyparse.

XHR a XHR2 s CORS

XHR může být jak synchronní, tak asynchronní. Také je to jediné API, které (záměrně) umožňuje odesílání synchronních požadavků, takže další kód se začne vykonávat až po zpracování callbacku.

V XHR není vlastně nic nového, ale v XHR2 můžeme navíc zpracovávat i uploady souborů, a proto je zde událost progress, která informuje o stavu uploadu, respektive downloadu.

Další novinka v XHR2 je podpora Cross-Origin Resource Sharing (CORS – viz článek o CORS na Zdrojáku). To znamená, že můžete posílat XHR i na jiné domény (ale pouze tehdy, když to server dovolí).

Dotaz je stejný jako u XHR:

    var client = new XMLHttpRequest();
    client.onreadystatechange = function () {
     if (this.readyState == 4 && this.status == 200) {
      alert('The most awesome-est person to follow: ' + this.responseText);
     }
    };
    client.open('GET', '/no-cors');
    client.send();

Na adrese http://remyshar­p.com/demo/cor­s.php je umístěn následující PHP skript:

    <?php
    header('Access-Control-Allow-Origin: *');
    ?>
    @rem

To umožňuje komukoliv posílat XHR požadavky na tento konkrétní skript. Pokud spustíme následující kód v libovolném prohlížeči, který podporuje XHR2, požadavek odeslaný na jinou doménu uspěje!

    var client = new XMLHttpRequest();
    client.onreadystatechange = function () {
     if (this.readyState == 4 && this.status == 200) {
      alert('The most awesome-est person to follow: ' + this.responseText);
     }
    };
    client.open('GET', 'http://remysharp.com/demo/cors.php');
    client.send();

Zde je funkční příklad s CORS. (Také je možné jej libovolně upravovat.)

Nutno poznamenat, že IE8 sice podporuje CORS, ale ne XHR2 (žádné překvapení). Je proto nutné použít proprietární (fuj!) objekt XDomainRequest. Vynikající článek, který popisuje, jak se s těmito rozdíly vypořádat, napsal Nicholas C. Zakas.

Podpora XHR a XHR2 s CORS

  • XHR je dnes již docela běžný (v IE6 je nutné použít ActiveXObject),
  • XHR2 s CORS je možné použít v Safari a MobileSafari, Firefox 3.5, Chrome a IE8 (pomocí XDomainRequest).

postMessage

Toto API je už poněkud starší, ale stále velmi užitečné, pokud chcete obejít omezení same-origin v XHR. Pokud máte iframe dokument, který přijímá onmessage události z vašeho zdroje (například z vaší stránky), můžete komunikovat mezi různými doménami.

Například stránka, která přijímá onmessage události, může obsahovat následující kód:

    window.onmessage = function (event) {
      if (event.origin == 'mytrustedsite.com') {
        alert('my trusted site said: ' + event.data);
      }
    };

Nyní lze vložit iframe do stránky, a pomocí DOM node posílat data:

    // kde 'iframe' je náš iframe v DOM
    iframe.contentWindow.postMessage("hello there", location.host);

Díky tomu jsme schopni posílat textové řetězce mezi dvěma doménami. (Pamatujte, že lze použít funkcí JSON.stringify a JSON.parse, pokud potřebujete posílat jiná než textová data.)

Podpora postMessage

  • Chrome
  • Safari
  • Opera
  • Firefox
  • IE8

Zde je ukázka využívající postMessage .

Ještě dodejme, že existuje projekt EasyXDM, který umožňuje cross domain messaging v prohlížečích IE6 a vyšší (společně s ostatními prohlížeči). Rozhodně stojí za nahlédnutí, pokud musíte pracovat se starými prohlížeči.

Web Sockets

Websockets (viz článek o WebSockets) jsou do jisté míry náhradou za Comet (viz Kometa přináší web v reálném čase). Zatímco Comet je workaround, který umožňuje odesílání zpráv ze strany serveru v reálném čase, web sockets API toto umožňuje nativně.

Websockets se používají k posílání zpráv směrem k a od serveru – jinak řečeno jsou to obousměrné sockety. V porovnání s ostatními technologiemi lze webové sockety použít i mezi doménami a nejste omezeni pravidlem same-origin. To například znamená, že se na své stránce můžete připojit na Twitter stream a získávat data v reálném čase (pokud uživatelův prohlížeč podporuje webové sockety).

Poté, co je socket otevřen, můžete odesílat data. Komunikační model vypadá takto:

    var ws = new WebSocket('ws://somesite.com/updates');

    ws.onmessage = function (event) {
      alert(event.data);
    };

    ws.onopen = function () {
      ws.send('yay! we connected!');
    };

Jakmile je socket jednou uzavřen, nemůže být znova využit. Neexistuje totiž žádná explicitní metoda pro jeho otevření, socket je otevřen ihned jakmile je vytvořen WebSocket objekt.

Toto API je velmi jednoduché, ale lidé se často ptají: „co je na straně serveru?“ Známé je použití Node, ale lze použít i Nginx, nebo Jetty. Funkční ukázka (odkaz níže) obsahuje i kód běžící na straně serveru.

Podívejte se na funkční ukázku využívající webové sockety.

Podpora websockets

  • Chrome
  • Safari a MobileSafari

Vynikající projekt, který implementuje webové sockety ve Flashi je web-socket.js. Jakmile jej vložíte do své aplikace, můžete využívat webové sockety skoro jako by byly podporované nativně.

Na začátku prosince 2010 se objevily bezpečnostní problémy s touto technologií, a proto byly z Firefoxu a Opery odstraněny. Mozilla však informovala, že se znovu objeví ve Firefoxu verze 4.0.1 (pozn. překladatele: ve Firefoxu 4 je tato technologie stále zakázána, ale lze ji ručně zapnout).

Server-Sent Events

Rozhraní pro Server-Sent Events se poprvé objevilo v Opeře v roce 2006 a používalo se k odesílání událostí ze serveru směrem ke klientovi. Nutno poznamenat, že klient nemůže odesílat zprávy na server pomocí EventSource (SSE) – může pouze události přijímat.

Toto API používá onmessage model, EventSource object a je omezeno pravidlem same-origin.

    var es = new EventSource('/sse');
    es.onopen = function () {
      console.log('opened stream');
    };

    es.onmessage = function (event) {
      console.log('new message: ' + event.data);
    };

SSE se automaticky připojí v okamžiku vzniku objektu EventSource (podobně jako je tomu u webových socketů) a poté spustí událost onopen. Jakmile klient přijme ze serveru novou zprávu, zavolá se onmessage callback.

Zde je ukázka Server-Sent Events.

Důležité je, aby server po odeslání zprávy neuzavřel spojení s klientem-prohlížečem. Pokud se tak stane, API se přepne do polling módu a klient začne pravidelně posílat dotazy na server. Jakmile je API v tomto módu, nijak se SSE neliší od XHR dotazu a onopen se bude spouštět opakovaně (na tento problém jsem narazil když jsem poprvé publikoval tento článek – pozn. aut.).

Serverovou část lze nalézt zde: custom-echo.js (používá Node.js server). Je zde trochu více kódu než by se dalo očekávat. To proto, že skript dělá více věcí:

  1. zpracovává HTTP požadavky,
  2. zpracovává server-sent events a neuzavírá spojení,
  3. nastaví webový socket a jakmile přijde nové spojení, odešlou se skrz SSE všechna aktuálně běžící sezení.

Podpora SSE

  • Opera 11
  • Safari a MobileSafari
  • Chrome

Web Workers

Web Workers jsou způsob, jak vytvořit nové vlákno uvnitř prohlížeče (viz samostatný článek o Web Workers). Tuto technologii zde uvádíme proto, že způsob, jakým se s Web Workers komunikuje, je podobný technologiím popsaným výše. Upozorňuji, že se nejedná o komunikaci mezi klientem a serverem, můžeme si to představit jako druhé okno prohlížeče, ve kterém se vykonává JavaScriptový kód.

K čemu je to dobré? Řekněme, že máte spoustu JavaScriptu a UI přestává reagovat. To je kvůli tomu, že se celá aplikace chová jako jednovláknová (doopravdy tomu tak není, ale z pohledu renderování stránky a JavaScriptu ano). V tomto případě lze náročný JS kód přenést do Web Workers a díky tomu bude UI fungovat plynule.

Je důležité vědět, že Web Workers se spouští v sand-boxovaném prostředí a tím pádem nemá kód přístup k DOM. Navíc, komunikace je možná pouze skrze funkce onmessagepostMessage.

Následující aplikace umí vytvořit a odeslat zprávy kódu, který běží ve Web Workers:

    var worker = new Worker('bigjob.js');
      worker.onmessage = function (event) {
      alert('Message from worker: ' + event.data); // pamatujte -- event.data je řetězec!
    };

    worker.postMessage('task=job1');

V souboru bigjob.js spouštíme nějaký výpočetně náročný kód, v němž můžeme přijímat zprávy, podobně jako jsme to dělali v předchozích příkladech. Také můžeme odesílat zprávy zpět:

    this.onmessage = function (event) {
        var job = event.data;
        if (job == 'task=job1') {
          job1();
        } else if (job == 'task=job2') {
          job2();
        }
    };

    // pouze příklad
    function job1() {
      // nějaká náročná úloha
      while (working) {
        // pokračuj v úloze
        this.postMessage('job1 ' + amountComplete + '% complete');
      }
      this.postMessage('job1 100% complete');
     }

Web Workers toho umí mnohem více než jen spouštět kód v druhém vlákně. Příklad výše ukázal, jak můžeme s WW komunikovat a jak je toto API podobné výše popsaným technologiím.

Podpora Web Workers

  • Chrome
  • Safari
  • Opera
  • Firefox

Závěrem

Výše popsané metody komunikace mezi klientem a serverem v HTML5 byly jen špičkou ledovce. Již nejsme odkázáni na metody s omezením same-origin, na který narážíme při použití čistého Ajaxu. V podstatě již máme k dispozici (od IE8) velmi slušnou cross-domain komunikaci.

Autor sám je nejvíce nadšen z webových socketů a podpory CORS v API, které nabízí služby jako Flickr, Twitter a URL zkracovače.

Co s tím dokážete udělat?

Je studentem fakulty elektrotechniky a komunikačních technologií na VUT v Brně. V roce 2004 objevil GNU/Linux a od té doby se zajímá o open-source a programování.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 10

Přehled komentářů

Mario Vejlupek prezdivka?
eL Re: prezdivka?
starenka opera a websocket
starenka WebWorker
Oxymoron vývojová prostředí
BoB2176 Re: vývojová prostředí
and Re: vývojová prostředí
lol Re: vývojová prostředí
OS v ajaxu Re: vývojová prostředí
Martin Malý Re: vývojová prostředí
Zdroj: https://www.zdrojak.cz/?p=3485