Ormai da qualche anno il web non è più un media da leggere: l'uso di applicazioni online (dalle email, ai documenti, ai social network) per le attività di ogni giorno è in continuo aumento, come lo sono i siti web che vanno oltre il semplice mostrare informazioni permettendo interazioni complesse lato utente.
La prima conseguenza di questa evoluzione è che gli sviluppatori hanno un crescete bisogno di tracciare l'utente nelle sue attività per renderne l'esperienza di navigazione più efficace, fluida e gratificante.
Di fronte a queste esigenze, l'unica soluzione lato client disponibile finora era rappresentata dai cookie.
Salvataggio lato client con Cookie
Tecnicamente i cookie sono dei frammenti di testo generati da una specifica richiesta del server web e salvati nel browser dell'utente per essere scambiati nei successivi accessi allo stesso dominio.
Il vantaggio dei cookie è che possono essere persistenti, cioè sopravvivere alla sessione corrente per essere richiamati in sessioni successive.
Allo stesso tempo, l'uso spesso fraudolento di cookie spinge molti utenti a disabilitarli oppure a ricorrere a sistemi di pulizia periodica dei dati di navigazione del browser.
Il maggiore svantaggio a livello di programmazione è che la gestione dei cookie lato client è legata esclusivamente alla proprietà document.cookie
, dalla quale è possibile ricavare una stringa relativa ai cookie del documento corrente comprendenti i valori impostati, il dominio e il percorso relativo di riferimento nonché l'eventuale data di scadenza.
Poiché la modifica e la lettura dei dati non sempre è immediata, alcune librerie mettono a disposizione metodi nativi per gestire i cookie con facilità, come ad esempio fanno MooTools e YUI.
Svantaggi dei cookie
In generale gli svantaggi relativi all'uso dei cookie sono:
- spazio di salvataggio limitato: i cookie possono salvare fine a 4KB di dati;
- struttura semplice: i dati salvati sono limitati a coppie chiave=valore;
- problemi di sessione: difficilmente i cookie riescono a distinguere due sessioni concorrenti sullo stesso browser ma in schede distinte;
- problemi di sicurezza: i cookie possono essere facilmente manipolati rappresentando un buco nella sicurezza dell'applicazione.
Web Storage
La crescente domanda di un sistema di archiviazione dei dati più efficiente dei cookie ha portato alla formulazione delle specifiche sul Web Storage che, dapprima contemplate nel documento di HTML5, sono ora indipendenti.
Il funzionamento del Web Storage non è diverso da quello dei cookie, in quanto i dati vengono sempre salvati sul client dell'utente, tuttavia i vantaggi derivanti dall'uso di questa tecnologia sono notevoli:
- maggior spazio: a seconda dei browser lo spazio disponibile per salvare i dati va da 5MB in su;
- gestione di sessioni multiple: i dati salvati sono condivisi sulle schede che hanno la stessa origine.
Secondo quanto riportato nelle specifiche HTML5, per determinare l'origine di un documento si deve fare riferimento alla struttura schema/host/porta dell'indirizzo. Ad esempio, i dati di storage perhttp://www.miosito.it/
saranno accessibili da tutte le tab che puntano ad una stessa paginahttp://www.miosito.it/carrello.html
, ma anche dagli indirizzihttp://www.miosito.it/cartella1/
ehttp://www.miosito.it/cartella2/
. Al contrario sono considerate diverse le originihttp://sub.miosito.it/
ehttps://www.miosito.it/
; - API nativa: i browser che supportano il web storage offrono una serie di metodi e proprietà (API) per leggere e manipolare i dati salvati.
Session Storage e Local Storage
Sebbene le API Web Storage siano uniche, gli oggetti contenitori previsti dalla specifica sono due:
- session storage: fa capo all'oggetto
sessionStorage
. I dati salvati in questo tipo di contenitore saranno disponibili solo durante la sessione corrente e fino alla chiusura della tab/finestra del browser; - local storage: fa capo a
localStorage
. I dati saranno persistenti sul client dell'utente finché questi non deciderà di rimuoverli.
Supporto dei browser
Prima di vedere i metodi di interazione con i contenitori Web Storage, va notato che il supporto dei browser a questa tecnologia non è del tutto scontato, soprattutto per le vecchie versioni.
Al momento il supporto completo è offerto da Firefox 3.5, Internet Explorer 8, Opera 10.50, Chrome 4 e Safari 4, mentre per le versioni precedenti sono disponibili soluzioni alternative che vedremo in seguito.
Web Storage API
Come detto in precedenza, sessionStorage
e localStorage
condividono gli stessi metodi e la stessa struttura dati. Semplificando, possiamo immaginare di dover interagire con un oggetto JavaScript 'chiave' : 'valore'
utilizzando i seguenti metodi:
setItem('chiave', 'valore')
: imposta un nuovo valore nel contenitore;getItem('chiave')
: restituisce il valore di una specifica chiave, se la chiave non è impostata restituiscenull
;key(indice)
: restituisce una chiave in base alla sua posizione all'interno del contenitore, se la chiave relativa all'indice non è impostata restituiscenull
;removeItem('chiave')
: rimuove una specifica coppia chiave / valore;clear()
: cancella tutti i dati salvati per l'origine corrente.
Nell'esempio qui sotto utilizzeremo i due primi metodi sul contenitore SessionStorage
:
//Imposto dei dati temporanei
sessionStorage.setItem('nome_utente', 'Mario');
sessionStorage.setItem('cognome_utente', 'Rossi');
//ricavo il valore di una chiave specifica
sessionStorage.getItem('nome_utente'); // 'Mario'
Partendo da questo esempio è possibile realizzare uno scenario più complesso, in cui i dati di sessione vengono passati al contenitore localStorage
per renderli persistenti:
//ricavo la prima chiave del contenitore
//quindi estraggo il valore collegato
var chiave = sessionStorage.key(0); // 'nome_utente'
var nomeUtente = sessionStorage.getItem(chiave); // 'Mario'
//passo il suo valore al contenitore persistente
localStorage.setItem('tmp_utente', nomeUtente);
//resetto in contenitore di sessione
sessionStorage.clear();
//verifico che i dati di sessione siano stati cancellati
alert(sessionStorage.getItem('nome_utente')); // null
Oltre ai metodi citati, è possibile utilizzare una sintassi alternativa che sfrutta la natura di oggetto alla base dei contenitori Web Storage:
//impostare un valore
sessionStorage.nome_utente = 'Mario';
//ricavare un valore
var nomeUtente = sessionStorage.nome_utente;
//cancellare un valore
delete sessionStorage.nome_utente;
L'unica differenza fra i due approcci è che nel caso di una chiave non impostata, .getItem('nome_utente')
restituirà null
mentre .nome_utente
sarà undefined
.
Un'ultima proprietà interessante è .length
che rappresenta il numero di chiavi presenti nel contenitore:
alert(localStorage.length); // 0
localStorage.setItem('nome_utente', 'Mario');
alert(localStorage.length); // 1
Ecco un esempio pratico.
L'evento 'storage'
Oltre ai contenitori stessi, le specifiche prevedono anche l'implementazione di un evento storage
che viene lanciato al cambiamento dei dati in uno dei contenitori. Questo evento al momento ha un supporto limitato, eccone un metodo di implementazione e i valori ad esso collegati:
addEventListener('storage', function(e){
e.storageArea; // indica il contenitore: Session o Local
e.key; // la chiave il cui valore è stato modificato
e.oldValue; // valore precedente
e.newValue; // nuovo valore
e.url; //URL della pagina in cui il valore è stato modificato
});
Limiti attuali del Web Storage
Sebbene sia già largamente usabile in ambienti di produzione, il Web Storage è una tecnologia ancora giovane e per questo non priva di limiti.
Anzitutto, nonostante la loro architettura possa richiamare quella di un oggetto JavaScript, è importante sottolineare che al momento i dati salvati possono essere esclusivamente di tipo stringa sia per quanto riguarda le chiavi che i valori. Tutti i dati inseriti saranno perciò convertiti:
localStorage.setItem(1, 30);
typeof localStorage.key(0) // string
typeof localStorage.getItem('1') // string
Questo limita la possibilità di salvare dati complessi come oggetti JSON nei contenitori, se non ricorrendo alla conversione dei dati in stringa. Tale opzione è già disponibile nativamente nelle ultime versioni di molti browser (Internet Explorer 8, Firefox 3.5, Safari 4, Chrome 4 e Opera 10.50).
Tuttavia per utilizzare una soluzione cross-browser è consigliabile ricorrere ad una libreria esterna che implementi il supporto a JSON ove mancante: una di queste è JSON2.js:
var data = JSON.stringify({chiave1: 'valore1', chiave2: 'valore2'});
localStorage.setItem('data', data);
var datiConvertiti = JSON.parse( localStorage.data );
Mentre questo è il codice per Mootools 1.2:
var data = JSON.encode({chiave1: 'valore1', chiave2: 'valore2'});
localStorage.setItem('data', data);
var datiConvertiti = JSON.decode( localStorage.data );
jQuery offre solamente un'utility di decodifica, perciò per la codifica si deve comunque ricorrere ad una libreria esterna:
var datiConvertiti = $.parseJSON( localStorage.data );
Altre librerie che offrono supporto a JSON sono YUI, Prototype e Dojo.
Estendere la compatibilità
Il limite maggiore all'uso del Web Storage rimane comunque il fatto che le vecchie versioni dei browser non supportano tale tecnologia. Esistono tuttavia alcune soluzioni che prevedono dei meccanismi di fallback, che ricorrono a metodi alternativi per salvare i dati in assenza di Web Storage permettendo tuttavia di lavorare con un unica API.
Oltre ai cookie, le tecniche di salvataggio alternative sono solitamente Flash, Google Gears, globalStorage e userData (tecnica simile a Web Storage implementata in IE6 e 7).
Fra le soluzioni più interessanti troviamo jStorage (plugin per jQuery) e PersistJS. Un'altra soluzione basata sul ricorso ai soli cookie come fallback è stata presentata in un articolo di 24 ways da Remy Sharp.
Strumenti per gli sviluppatori
Un ultimo argomento riguarda gli strumenti offerti dai browser per lo sviluppo ed il debug delle applicazioni basate su Web Storage. Al momento solo gli strumenti per sviluppatori di Chrome, Safari e Opera (Dragonfly) presentano una tab dedicata alla lettura dei dati salvati nei contenitori, mentre Firebug permette di accedere agli oggetti richiamandoli dalla console.
Riferimenti
Di seguito alcuni utili riferimenti e approfondimenti sull'argomento:
- Documentazione ufficiale
- Tabella del supporto offerto dai browser (da aggiornare, ma comunque utile)
- jStorage: plugin per jQuery compatibile con i browser che non supportano il Web Storage