Vai al contenuto

Server-Sent Events in HTML5

Tradizionalmente in un’architettura client-server, come mostrato in figura, una pagina web residente nel client invia una richiesta al server per ricevere una risposta con dei dati. Con l’avvento dell’HTML5, e in particolare della libreria API Server-Sent Events, è possibile, per un server, inviare dei dati a una pagina web “in qualsiasi momento”, tramite dei messaggi push, senza che la pagina in questione ne faccia esplicita richiesta. I messaggi in arrivo possono essere trattati come eventi + dati all’interno della pagina web. 

client-server

Lo sviluppo di un’applicazione web che utilizza le API Server-Sent Events è abbastanza facile. Avrete bisogno di un po’ di codice sul server per lo effettuare lo streaming degli eventi al client; per quanto riguarda il lato client, la gestione di tale eventi è identica a qualsiasi altro tipo di evento.

Le API Server-Sent Events sono contenute nell’interfaccia EventSource. Per aprire una connessione al server e iniziare a ricevere gli eventi, bisogna creare un nuovo oggetto EventSource, specificando l’URI dello script sul server che genera lo stream di eventi. Per esempio:

var evtSource = new EventSource("sse_test.php");

Una volta istanziato l’oggetto, è possibile iniziare  ad intercettare i messaggi che verranno creati dallo script in sse_test.php:

evtSource.onmessage = function(e) {
  var newElement = document.createElement("div");
  newElement.innerHTML = "message: " + e.data;
  eventContainer.appendChild(newElement);
}

Lo script sopra non fa altro che “ascoltare” eventuali messaggi in arrivo (cioè, dei messaggi standard dal server ) e aggiungere il testo del messaggio in un contenitore div che poi viene mostrato nella pagina.

È anche possibile ascoltare eventi personalizzati, utilizzando la funzione addEventListener():

evtSource.addEventListener("ping", function(e) {
  var newElement = document.createElement("div");
  var obj = JSON.parse(e.data);
  newElement.innerHTML = "ping at " + obj.time;
  eventList.appendChild(newElement);
}, false);

Questo codice è simile al precedente, tranne per il fatto che verrà chiamato solo quando il server invierà un messaggio di tipo ping al client.

Il formato del messaggio

Il messaggio che viene inviato dal server al client è un semplice streaming di testo in formato JSON, codificati in UTF-8. Ogni messaggio è separato da una coppia di caratteri speciali \n\n. Una riga del emessaggio che inizia con : è, in sostanza, una riga di commento e viene ignorata. La riga di commento può essere usata per impedire il timeout della connessione: un server può inviare periodicamente un commento per mantenere aperta la connessione.

Ogni messaggio è costituito da una o più righe di testo scritte secondo la notazione nomecampo: valore + \n

Campi

I campi che possono essere utilizzati in un messaggio sono 4. Altri campi, al di fuori di questi, vengono sostanzialmente ignorati.

  • event – rappresenta il tipo di evento. Se nel messaggio viene specificato questo campo, l’evento inviato al browser potrà essere intercettato solo utilizzando addEventListener(). L’handler onMessage() invece intercetta qualsiasi messaggio privo del campo event.
  • data – rappresenta il campo dati per il messaggio, cioè il contenuto che dovrebbe essere visualizzato sul browser. Quando EventSource() riceve più linee che iniziano con “data:”, li concatena, e inserisce un ritorno a capo \n tra ciascuno di essi.
  • id – rappresenta l’ID del messaggio.
  • retry – rappresenta il tempo di riconnessione in millisecondi da utilizzare quando si tenta di inviare un messaggio. Se non viene specificato un valore intero, il campo viene ignorato.

Esempi

Messaggi “data only”

In questo esempio, si ipotizza l’invio di tre messaggi. Il primo messaggio è solo un commento, poiché comincia con i due punti. Come accennato in precedenza, può essere utile come keep-alive della connessione se lo streaming di dati non è costante e c’è il rischio di far cadere la connessione. Il secondo messaggio contiene il campo data con il valore “testo di esempio“. Il terzo messaggio contiene il campo data con il valore “un altro messaggio \n con due linee“.

: questo e' uno stream di testo\n\n

data: testo di esempio\n\n

data: un altro messaggio\n
data: con due linee\n\n
Eventi specifici

In questo esempio abbiamo alcuni eventi specifici. Ciascun messaggio viene settato il campo event, con il nome della tipologia di evento, e il campo data il cui valore è specificato secondo la notazione JSON con i dati che poi il client “parserizzerà” a dovere.

event: userconnect\n
data: {"username": "bobby", "time": "02:33:48"}\n\n

event: usermessage\n
data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}\n\n

event: userdisconnect\n
data: {"username": "bobby", "time": "02:34:23"}\n\n

event: usermessage\n
data: {"username": "sean", "time": "02:34:36", "text": "Bye, bobby."}\n\n

Miscelazione e la congruenza

Ovviamente è possibile mescolare insieme in un unico flusso di dati sia messaggi generici (solo con il campo data) che messaggi personalizzati.

event: userconnect\n
data: {"username": "bobby", "time": "02:33:48"}\n\n

data: Here's a system message of some kind that will get used\n
data: to accomplish some task.\n\n

event: usermessage\n
data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}\n\n

 Risorse utili

http://dev.w3.org/html5/eventsource/