HTTP/2, detto anche HTTP/2.0, è la nuova versione del protocollo HTTP che rende le applicazioni web più veloci, snelle e robuste, consentendo di fare a meno di alcune tecniche di ottimizzazione adottate per porre rimedio ai limiti di HTTP/1.1. Tra gli obiettivi primari di HTTP/2 vi sono:
Le implementazioni per raggiungere tali obiettivi, che stavano alla base del progetto sperimentale SPDY di Google, consentono di aumentare i livelli di performance fino anche a raddoppiare la velocità di caricamento di una pagina web.
HTTP/2 mira inoltre ad essere retrocompatibile, infatti tutti i concetti chiave come status code, headers, metodi HTTP ecc.. rimangono inalterati, difatti il passaggio da HTTP/1.1 ad HTTP/2.0 non richiede alcuna modifica alle applicazioni.
Indice dei contenuti
Se sei uno sviluppatore probabilmente ti starai chiedendo perché hanno ribattezzato il protocollo HTTP/2.0 invece di HTTP/1.2 o similari? Il motivo sta nel cambiamento nel come i dati vengono scambiati tra client e server. Per raggiungere gli obiettivi elencati poc’anzi, HTTP/2 aggiunge un nuovo layer in formato binario non retrocompatibile con i server ed i client HTTP/1.x, motivo per cui si è deciso di incrementare la versione a 2.0.
Quindi il protocollo è retrocompatibile per quanto concerne le applicazioni web ma richiede un upgrade del web server e del browser ad una versione supportata. Chiusa questa parentesi, vediamo come funziona nel dettaglio questa nuova versione del protocollo HTTP.
A differenza di HTTP/1.1, i messaggi HTTP sono incapsulati e trasmessi tra client e server all’interno di un frame binario come rappresentato dalla figura sottostante.
Dall’immagine si nota come la semantica HTTP non viene alterata ma è la codifica durante la fase di trasmissione a cambiare. I dati, infatti, vengono suddivisi in messaggi e frame più piccoli i quali vengono codificati in binario e trasmessi.
Pertanto è necessario disporre di client e server in grado di utilizzare il nuovo meccanismo di codifica, una banalità che consente di rendere le applicazioni web praticamente identiche. Un toccasana per gli sviluppatori web che non dovranno effettuare alcuna modifica ai miliardi di siti web presenti in tutto il mondo per supportare il nuovo protocollo.
A differenza di HTTP/1.1, tutte le comunicazioni in HTTP/2 vengono effettuate mediante l’ausilio di un’unica connessione TCP. Gli header che compongono il pacchetto HTTP vengono suddivisi in frame codificati in binario che a loro volta vengono raggruppati in messaggi che appartengono a stream ben precisi, i quali vengono trasmessi mediante la connessione TCP aperta.
Ad ogni stream e frame viene assegnato un ID univoco che servirà a client e server per ricomporre il messaggio originale ed elaborare la richiesta. Questo consente di utilizzare la stessa connessione TCP per la trasmissione di diversi messaggi HTTP e grazie alla suddivisione in frame ne consente il download parallelo.
Naturalmente la trasmissione dei frame è regolamentata da un algoritmo di assegnazione delle priorità affinché l’ordine di trasmissione non comprometta le performance.
Con HTTP/1.1, per velocizzare il download delle risorse esterne e quindi velocizzare il tempo di rendering della pagina, il browser era obbligato ad aprire diverse connessioni TCP, una per ogni richiesta. Un male assoluto che ha portato gli sviluppatori ad adottare tecniche di minificazione e concatenazione di risorse critiche e immagini per ridurre il numero di richieste HTTP e quindi di connessioni.
L’introduzione del layer binario e la conseguente suddivisione dei pacchetti HTTP in frame bypassa queste limitazioni e consente di avviare una comunicazione in multiplexing, dove diversi frame facenti parte anche di diversi pacchetti/risorse possono essere trasmessi in rete per poi essere riassemblati grazie ai loro ID univoci.
Questo consente al client di scaricare in parallelo le risorse necessarie per effettuare il rendering della pagina. Com’è possibile notare dalla figura sottostante, infatti, mentre il client invia al server uno stream identificato dell’ID 5 il server invia al client gli stream 1 e 3 ad intervalli diversi, facenti capo a risorse diverse.
È possibile visualizzare in pratica questo comportamento analizzando il waterfall delle risorse di rete quando si visita un sito web con e senza supporto HTTP 2. Le immagini successive riportano il waterfall di Chrome DevTools dello stesso sito, prima e dopo l’applicazione di HTTP 2. È possibile notare come nel primo caso le risorse vengono scaricate in modalità sequenziale mentre nel secondo caso in parallelo.
Da notare come il tempo di download necessario per scaricare le risorse sia praticamente dimezzato rispetto alla versione HTTP/1.1. Il nuovo protocollo inoltre implementa un algoritmo per il controllo del flusso di trasmissione dati che mira a non sovraccaricare una delle due parti (client o server) con dati che non vuole o che non può in quel momento elaborare.
Come già detto più volte nei paragrafi precedenti, HTTP/2 supporta un’unica connessione TCP per origine che offre diversi benefici in termini di performance. Molte delle risorse che compongono una pagina web sono piccole al punto che l’apertura di una nuova connessione TCP con tutto quello che ne comporta, ovvero risoluzione DNS, TCP handshake, eventuale negoziazione TLS e tempo di download, risulta più lenta del download della risorsa stessa.
Inoltre l’utilizzo di un’unica connessione consente di ridurre il consumo di memoria ed overhead di CPU. La migrazione ad HTTP/2 quindi non va vista solo dal punto di vista della riduzione della latenza di rete ma anche come un’ottimizzazione delle risorse computazionali.
Una tipica pagina web è formata da una dozzina di risorse che vengono scoperte dal client durante il parsing HTML e successivamente richieste al server. HTTP/2 consente al server di anticipare al client questa scoperta e ridurre così il tempo necessario per richiedere il download di tali risorse. Questa caratteristica è nota come server push.
Praticamente, oltre alla risposta alla richiesta originale, il server può inviare al client risorse aggiuntive senza che sia il client a richiederle esplicitamente. Dalla figura sottostante il server invia al client la risposta allo stream 1 ma in più invia due ulteriori stream, 2 e 4, corrispondenti a risorse differenti, ad esempio uno script Javascript e un CSS che di per certo verranno utilizzati all’interno della pagina.
Il client può decidere se prendere o meno in considerazione il download della risorsa comunicata tramite server push. Ad esempio se la risorsa è già stata scaricata ed è disponibile in cache, il browser declinerà la richiesta.
Ogni pacchetto HTTP è composto da header in formato testo che riportano proprietà e caratteristiche della risorsa in fase di trasferimento. Mentre in HTTP/1.1 questi dati vengono sempre trasmessi in chiaro, compreso i cookie con tutto il loro peso, in HTTP/2 vengono compressi utilizzando il formato di compressione HPACK, applicando un algoritmo che consente di rimuovere tutto ciò che è duplicato, ottenendo header più snelli.
Per maggiori informazioni sul funzionamento di HPACK su HTTP/2 vi invito a leggere il documento IETF HPACK – Header Compression for HTTP/2.
Secondo i test condotti da KeyCDN, la compressione degli header riduce la loro dimensione di circa il 30%.
Per utilizzare HTTP/2 è richiesto l’utilizzo di HTTPS. Grazie ad HTTP/2 ed al suo multiplexing, le connessioni cifrate sono diventate molto più veloci delle classiche connessioni non sicure. Per verificarlo basta effettuare una comparazione di velocità tra HTTP e HTTPS.
Per verificare se un sito web supporta HTTP/2 basta visitarlo, aprire la Chrome DevTools, posizionarsi sul tab Network, cliccare con il tasto destro sulla tabella e abilitare la visualizzazione della colonna Protocol se non già visibile ed aggiornare la pagina. Se il sito supporta HTTP/2, le risorse scaricate dallo stesso avranno h2 come protocollo.
Alternativamente, per capire se il browser che stiamo utilizzando supporta HTTP/2 basta visitare il test online di Akamai che oltre a verificare il supporto effettuerà un test di velocità di download delle stesse immagini prima in HTTP/1.1 e poi in HTTP/2 per farvi notare la reale differenza nel tempo di caricamento.
Ad oggi più del 77% dei browser supporta HTTP/2, tuttavia alcuni non lo supportano ancora in tutte le sue caratteristiche. Di seguito la lista completa dei browser che supportano HTTP/2. È possibile verificare via via il supporto cliccando qui.
Per utilizzare HTTP/2 su Nginx occorre utilizzare una versione maggiore o uguale alla 1.9.5. Configurarlo è facilissimo:
server { listen 443 ssl http2 default_server; ssl_certificate /path/to/server.cert; ssl_certificate_key /path/to/server.key; ... }
Per utilizzare HTTP/2 su Apache occorre utilizzare una versione maggiore o uguale alla 2.4. Se è su un server Ubuntu LTS 16.04 occorre prima aggiornare il repository:
sudo add-apt-repository ppa:ondrej/apache2 sudo apt-get update sudo apt-get upgrade
Una volta installato Apache occorre abilitare il modulo http2:
sudo a2enmod http2
Dopodiché modificare il Virtual Host SSL ed aggiungere la direttiva Protocols:
<VirtualHost *:443> ServerAdmin webmaster@localhost ServerName your-domain.com SSLEngine On SSLCertificateFile /path/to/server.cert SSLCertificateKeyFile /path/to/server.key Protocols h2 http/1.1 ... </VirtualHost>
Riavviare Apache.
HTTP/2 consente out of the box di ottenere performance più elevate rispetto ad HTTP/1.1 grazie alle implementazioni che consentono di parallelizzare il download delle risorse ed anticiparne i tempi di richiesta, oltre che ad una maggiore velocità di trasmissione dovuta alla compressione dati.
Il passaggio da HTTP/1.1 ad HTTP/2 non comporta alcuna modifica dell’applicazione web ma tecniche di ottimizzazione utilizzate per HTTP/1.1 devono essere riviste in ottica HTTP/2, in particolar modo quelle che mirano a ridurre il numero di richieste HTTP.