HTTP: costruisci la richiesta, leggi la risposta
HTTP è il protocollo che stai usando proprio adesso per leggere questa pagina, ed è fatto di testo: si può scrivere a mano. Qui ci sono quattro giochi — monta una richiesta e guarda il server rifiutarla, indovina il codice giusto, decidi se la richiesta parte davvero, e conta i giri di andata e ritorno che separano HTTP/1.0 da HTTP/2.
Quando il browser chiede una pagina, manda al server un pezzo di testo, fatto così. Qui lo rimonti tu, riga per riga — e il server risponde come risponderebbe uno vero: gli errori che ottieni sono errori veri.
GET /pagina.html HTTP/1.1
cosa vuoi, di preciso — una sola
Host: esempio.it
quante ne servono, una per riga
Accept: text/html
(qui non c'è scritto niente)
obbligatoria: dice «le intestazioni finiscono qui»
nome=Ada&voto=10
solo se stai mandando dei dati
Obiettivo: comporre una richiesta che il server accetti con 200 OK. Non servono tutti i pezzi qui sotto — servono quelli giusti, nell'ordine giusto. Tre bastano.
Ogni risposta HTTP comincia con un numero di tre cifre, e la prima cifra dice già quasi tutto: 4xx hai sbagliato tu, 5xx ha sbagliato il server, 3xx la cosa è altrove. Ti descrivo una situazione, tu scegli il numero. Se sbagli non ti dico qual è quello giusto: la scelta si spegne e riprovi.
Che codice risponde il server?
Il modo migliore di velocizzare una richiesta è non farla. Ogni volta che il browser sta per chiedere qualcosa che ha già, si fa due domande in quest'ordine: 1) il tempo dichiarato dal server è scaduto? Se no, non parte niente. 2) Se è scaduto, il file sul server è cambiato? Se no torna un 304 col corpo vuoto, se sì torna tutto. Prova a rispondere tu.
La richiesta parte, o no?
Una pagina web non è un file: sono decine di file (HTML, fogli di stile, script, immagini), e ognuno va chiesto. Il RTT è quanto ci mette una domanda ad andare e la risposta a tornare. Muovi i due cursori e guarda quanti giri servono alle quattro versioni di HTTP per la stessa identica pagina: cambia solo il modo di chiedere, non la banda.
Gli stessi byte, quattro modi di chiederli
Come funziona
Anatomia di una richiesta
Una richiesta HTTP è testo, e ha quattro parti in ordine fisso: la riga di richiesta (metodo, percorso, versione), le intestazioni (una per riga, Nome: valore), una riga vuota, e infine il corpo — che c'è solo se serve.
La riga vuota non è estetica: è il delimitatore che dice al server «le intestazioni finiscono qui». Senza quella riga il server continua ad aspettare intestazioni che non arrivano mai, e la connessione muore di timeout. È l'errore più istruttivo del primo gioco, ed è la ragione per cui i protocolli testuali hanno bisogno di un modo esplicito per dire «ho finito».
E Host: è obbligatoria in HTTP/1.1 per una ragione molto concreta: su uno stesso indirizzo IP vivono centinaia di siti diversi. Senza quella riga il server ha ricevuto il pacchetto ma non sa quale sito gli stai chiedendo. È l'intestazione che ha reso possibile l'hosting condiviso — e infatti è arrivata con la 1.1, non c'era nella 1.0.
I metodi, e due proprietà che li classificano
| Metodo | Cosa fa | Sicuro | Idempotente |
|---|---|---|---|
| GET | chiedi una risorsa | sì | sì |
| HEAD | solo le intestazioni, niente corpo | sì | sì |
| POST | manda dati, crea qualcosa | no | no |
| PUT | sostituisci la risorsa | no | sì |
| DELETE | cancella la risorsa | no | sì |
Sicuro vuol dire che non modifica niente. Idempotente vuol dire che ripeterlo dà lo stesso risultato di farlo una volta sola: cancellare due volte lo stesso file lascia lo stesso mondo. Ed è per questo che il browser ti chiede «vuoi rimandare il modulo?» quando ricarichi una pagina dopo un POST: quello, idempotente non è, e rifarlo comprerebbe due volte.
I codici: la prima cifra è già una risposta
| Fascia | Significato | Di chi è la colpa | Ha senso ritentare? |
|---|---|---|---|
| 1xx | informativo, aspetta | — | — |
| 2xx | fatto | — | — |
| 3xx | è altrove, o ce l'hai già | — | segui l'indicazione |
| 4xx | hai sbagliato tu | del client | no, non così |
| 5xx | ho sbagliato io | del server | sì, fra poco |
La cache: la richiesta che non parte è la più veloce
Ci sono due meccanismi, e il secondo gioco serve a non confonderli.
- Cache con scadenza — non parte proprio niente
- Il server dichiara Cache-Control: max-age=3600: per un'ora il browser usa la copia locale senza contattare nessuno. Zero pacchetti, zero attesa.
- Richiesta condizionale — parte poco, torna quasi niente
- Scaduto il tempo, il browser non riscarica alla cieca: allega l'impronta che possiede (If-None-Match: "v3-8f2c") e chiede se è cambiato. Se non è cambiato torna 304 Not Modified, con il corpo vuoto.
Il guadagno si conta: per un'immagine da 500 kB rimasta uguale, un 304 pesa circa 200 byte contro 500.000. Si risparmia il 99,96% del traffico — al prezzo di un giro di andata e ritorno, che con la scadenza invece non si paga affatto.
Le versioni, e la matematica dei giri
È il calcolo più efficace di tutto il capitolo, ed è quello del quarto gioco. Con 30 risorse, RTT 40 ms e 6 connessioni parallele:
| Versione | Conteggio dei giri | Totale | Tempo |
|---|---|---|---|
| 1.0, una connessione alla volta | 30 × (1 + 1) | 60 RTT | 2400 ms |
| 1.0, 6 connessioni parallele | ⌈30/6⌉ × 2 | 10 RTT | 400 ms |
| 1.1 keep-alive, 6 connessioni | 1 + ⌈30/6⌉ | 6 RTT | 240 ms |
| 2, una connessione multiplata | 1 + 1 | 2 RTT | 80 ms |
Trenta volte più veloce, senza che la banda c'entri niente: è tutto tempo di attesa, non di trasferimento. È la dimostrazione più netta che sulla rete moderna il collo di bottiglia è quasi sempre la latenza, non la velocità della linea. Comprare una linea più veloce non sposta questi numeri di un millisecondo.
Il salto da 1.1 a 2 elimina il blocco in testa alla coda: in HTTP/1.1 le risposte devono arrivare nell'ordine delle richieste, quindi una risorsa lenta blocca tutte quelle dietro. HTTP/2 spezza tutto in frame etichettati, che possono arrivare mescolati. Ne resta però uno più sottile: se si perde un solo segmento TCP, TCP blocca la consegna di tutti i flussi finché non l'ha recuperato — perché TCP vede un flusso di byte e non sa niente dei flussi HTTP che ci viaggiano dentro. È esattamente il problema che HTTP/3 risolve abbandonando TCP per QUIC.
HTTP non ha memoria
Ogni richiesta è un foglio bianco: il server non ricorda nulla della precedente. Se resti «loggato» è perché il browser riallega ogni volta un cookie che il server gli ha dato — non perché qualcuno si ricordi di te. Tutto ciò che sembra continuità, in HTTP, è un'informazione rispedita ogni singola volta.
HTTP è il contenuto della busta più interna: per vedere le altre tre che gli si chiudono intorno, apri Viaggio nel TCP/IP. La porta 80 e la 443 sono spiegate in Le porte e la quadrupla, e il nome del sito diventa un indirizzo in Dal nome all'indirizzo.
Ripetizioni e tutoring con un docente di ruolo
Matematica, fisica e informatica. Un metodo, non solo esercizi: si parte da come funziona.