Categorie
Javascript Programmazione

{JS} API di comunicazione: Server Sent Events (SSE)

Cos’è Server Sent Events API?

Server Sent Events API (SSE) detta anche “EventSource”, rappresenta un altra tipologia di comunicazione, connessione e richiesta al server.

Una richiesta HTTP è una connessione con il Web Server.

Finora con AJAX e FETCH API abbiamo inviato delle richieste al server che ci consentono di aggiornare componenti della nostra app/sito senza dover ricaricare la pagina; questo tipo di richiesta però inizia-e-termina tant’è vero che per ogni aggiornamento dovremo aprire più richieste e potremmo avere la necessità di aprire molteplici richieste per aggiornare lo stesso elemento della nostra pagina.

Potremmo quindi in alcuni casi avere l’esigenza di elaborare dati e aggiornare elementi in tempo-reale.

Senza la SSE API avremmo dovuto provvedere a creare un meccanismo di polling che a intervalli regolari invii una richiesta al server per verificare l’esistenza di nuove informazioni;
Tutto questo avrebbe portato ad un speco delle risorse del sistema ed un rallentamento dell’esecuzione dell’applicativo.

Note: Polling, in informatica, indica la verifica ciclica di tutte le unità o periferiche di input/output da parte del sistema operativo di un personal computer.
Questa attività impegna molto del tempo di funzionamento del spreco di risorse del sistema ed un consequenziale rallentando delle esecuzione dell'applicativo.

Con SSE API possiamo metterci in ascolto di eventi generati dal server e gestirli quando il server ha qualcosa da comunicarci.

Più semplicemente si tratta di una connessione costante che inizia e non termina fino a quando non riceve un comando di terminarla.

new EventSource()

Per creare questo tipo di connessione la SSE API mette a disposizione una particolare classe che prende il nome di “EventSoruce”:

var connessioneContinua = new EventSource(url);

Pensiamo alla classe “EventSource” come ad un parente stretto di “XmlHttpRequest” con caratteristiche di connessione differenti:

XmlHttpRequest/fetchla connessione inizia e termina
EventSourcela connessione rimane costante

Aprire una connessione

Con l’utilizzo della classe mediante l’istruzione “new” apriamo di fatto una nuova connessione.

Aperta la connessione, i messaggi/dati in arrivo dal server saranno consegnati al tuo codice sotto forma di eventi.

Proprietà e metodi

L’istanza creata eredità alcune proprietà e metodi per la gestione della connessione permanente.

ProprietàDescrizione
connessioneContinua.readyStaterestituisce un numero che rappresenta lo stato della connessione;
CONNECTING 0, OPEN 1 o CLOSED 2
connessioneContinua.CONNETING
connessioneContinua.OPEN
connessioneContinua.CLOSED
restituiscono true/false in base al valore della proprietà .readyState
connessioneContinua.urlrestituisce una stringa che rappresenta l’URL della sorgente
connessioneContinua.withCredentialsrestitusice valore booleano true/false che indica se l’ 
EventSource oggetto è stato istanziato con credenziali cross-origin
MetodiDescrizione
connessioneContinua.close()Chiude la connessione, se presente, e imposta l’ 
readyStateattributo su 
CLOSED
Cross-origin

Per motivi di sicurezza i browser limitano le richieste HTTP se le richieste HTTP sono inviate verso l’esterno della nostra app/sito.
Ciò significa che un’applicazione Web che utilizza API può richiedere risorse solo dalla stessa origine da cui è stata caricata l’applicazione.
Il codice JavaScript front-end che parte da https://primodomiono.com ed invia una richiesta HTTP verso https://secondodominio.com/data.json sarà bloccata come comportamento standard a meno che la risposta da altre origini non includa le intestazioni CORS corrette.

Eventi

Abbiamo detto che una volta aperta la connessione, i messaggi/dati in arrivo dal server saranno consegnati sotto forma di eventi:

EventoDescrizione
openl’evento si attiva quando è stata stabilita la connessione
errorl’evento si attiva quando non è stato possibile effettuare la connessione
messagel’evento si attiva quando i dati vengono ricevuti; può chiaramente ripetersi
open event

L’evento “open” rintraccia l’effettiva apertura di una connessione-permanente; l’esempio che segue mostra il suo utilizzo:

connessioneContinua.onopen = function() {
    console.log("Connessione con il server aperta.");
  };
error event

Allo stesso modo è possibile rintracciare una connessione fallita e che quindi ha avuto esito negativo

connessioneContinua.onerror = function() {
    console.log("Connessione fallita con il server.");
  };

message event

L’evento “message” rappresenta il cuore di una connessione “EventSource”; l’evento si scatena nel momento in cui qualcosa avviene o meglio qualche dato è inviato.

var connessioneContinua = new EventSource('https://www.cinquepuntozero.it/file.php');

var listaEventi = document.querySelector('ul');

connessioneContinua.onmessage = function(event){
  var nuovoElemento = document.createElement("li");

  nuovoElemento.textContent = `message: ${event.data}`;
  listaEventi.appendChild(nuovoElemento);
}

Nell’esempio qui sopra abbiamo aperto una nuova connessione e memorizzata la posizione di un elemento <ul> presente nel dom.
Nella funzione contenuta all’interno dell’evento “message” abbiamo dichiarato che quando un nuovo dato è inviato sarà creato un nuovo elemento <li>.
Al suo interno sarà inserito del contenuto testuale mediante la proprietà “.textContent” e mediante la proprietà “.data”, dell’oggetto evento, sarà inserito il dato ricevuto.
Infine facciamo appendere alla lista il nuovo elemento creato.

Chiudere la connessione

Una connessione aperta rimane continua sino al comando di chiusura.
Il comando è possibile darlo mediante il metodo .close()

button.onclick = function() {
    console.log('Connessione chiusa.');
    connessioneContinua.close();
  };

Come il server invia i dati

Abbiamo visto il funzionamento di “EventSource” lato front-end ma per comprende al meglio il suo funzionamento dobbiamo conoscere, seppur superficialmente, come il server invia lato backend i dati.

Inanzitutto il Content-Type associato alla risposta da parte del server sarà text/event-stream.

Di seguito un esempio di codice PHP per la gestione delle risposte lato back-end:

header('Content-Type: text/event-stream');
echo "data: messaggio\n\n";
flush();

Il contenuto del messaggio/dato è costituito da una riga che inizia con “data:” e termina con due fine riga consecutivi “\n\n”

data: messaggio\n\n

La presenza di due ritorni a capo consecutivi indica la fine del messaggio.

Il server può rispondere con un messaggio multi riga ma tutte le righe devono iniziare con “data:”

data: messaggio 
data: su più righe\n\n

Il server può rispondere in più formati il seguente esempio mostra com’è strutturo un messaggio json

data: { "codice": "123", 
data: "msg": "messaggio dal server" }\n\n

Il messaggio del server può contenere un identificatore mediante “id:”:

id: 12345 
data: { "codice": "123", 
data: "msg": "messaggio dal server" }\n\n

Lato server è anche possibile assegnare un nome d’evento custom a ciascun messaggio mediante “event:”

event: update 
data: { "codice": "567", 
data: "msg": "Nuovo messaggio dal server" }

eventi custom

Abbiamo lasciato per ultimo questo paragrafo il quanto prima dovevamo conoscere come il server risponde.
Lato front-end è possibile gestire eventi custom solo ed esclusivamente con il metodo .addEventListener e non con la formula “on”

connessioneContinua.addEventListener('update', function(event){
console.log(`Un nuovo dato ricevuto: ${event.data}`);
});

L’utilizzo che ne abbiamo fatto nell’esempio qui sopra risulta banale anche perché l’avremmo potuto contenere direttamente nell’evento “message” ma ci fa comprendere il suo funzionamento.

L’evento “update” sarà scatenabile solo se contenuto all’interno del messaggio del server “event: update” visto poco sopra.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *