This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Sunday, 28 December 2025
HTTP non si è evoluto. forzato cambiare con la fisica, la latenza e l'uso improprio.
Ogni versione esiste perché quella precedente ha colpito un vincolo duro. Se capisci questi vincoli, capisci perché il web funziona come fa - e perché così tante "migliori pratiche" sono in realtà workaround per le limitazioni del protocollo che abbiamo trascinato intorno per trent'anni.
Sto costruendo applicazioni web dal 1997. Ho debuggato HTTP/1.0 tempeste di connessione, guardato browser aprire sei connessioni per host come una "caratteristica," maledetto a HTTP/2 TCP head-of-line blocco su reti mobili, e infine visto HTTP/3 ammettere quello che sapevamo da sempre: la rete è il problema.
Questo non e' un tutorial sul protocollo, e' la storia di come siamo arrivati qui.
HTTP/1.0 è stato progettato nel 1996 per un mondo che non esiste più. Per capire perché ha funzionato, è necessario capire cosa significava "il web" nel 1996:
In questo mondo, il collo di bottiglia era larghezza di bandaUna pagina da 50KB ci ha messo 15 secondi per scaricare il dialup.
A cosa serve ottimizzato HTTP/1.0 per:
GET /index.html HTTP/1.0
Host: example.com
HTTP/1.0 200 OK
Content-Type: text/html
<html>...
Semplice. Elegante. Perfetto per il 1996. E completamente inutilizzabile per qualsiasi cosa oltre il recupero di documenti.
Poi la ragnatela e' cambiata.
Nel 1998, le pagine non erano solo documenti. Avevano fogli di stile, JavaScript, immagini multiple. Una singola pagina potrebbe avere bisogno di 20-30 risorse separate.
Ogni singola richiesta richiesta richiesta:
Una pagina con 20 risorse ha significato 20 strette di mano TCP. Su una connessione di latenza 200ms (ancora comune), che è 4 secondi di Solo una stretta di mano. prima di qualsiasi contenuto trasferito.
L'ipotesi fondamentale di HTTP/1.0:
Il tempo era scadente.
Nel 1996, era. La larghezza di banda era il collo di bottiglia. Nel 1999, la larghezza di banda stava migliorando, ma La latenza non era - e all'improvviso quei viaggi di andata e ritorno contavano.
HTTP/1.0 è stato progettato per i documenti. Il web era diventato una piattaforma di applicazioni. Qualcosa doveva dare.
HTTP/1.1 è arrivato nel 1997, proprio mentre il web stava esplodendo. Il boom di dotcom stava iniziando. Ogni azienda aveva bisogno di un sito web. Le pagine web stavano diventando complesse - tabelle per il layout, JavaScript per l'interattività, immagini ovunque.
La pressione era chiara: connessione-per-richiesta stava uccidendo le prestazioni. Ma completamente riprogettare HTTP non era un'opzione. Troppa infrastruttura già dipendeva da esso. La soluzione doveva essere retro-compatibile.
Che cosa è cambiato:
Connection: keep-alive per impostazione predefinita) - riutilizzare la connessione TCPCache-Control, ETag, richieste condizionali)Che cosa non è cambiato:
GET /page.html HTTP/1.1
Host: example.com
Connection: keep-alive
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Cache-Control: max-age=3600
...
HTTP/1.1 in realtà non ha risolto il problema delle prestazioni.
Il Pipelining e' stato un fallimento. La specifica ha permesso l'invio di richieste multiple su una connessione, ma:
Così i browser truffati. Invece di fissare il protocollo, hanno lavorato intorno:
static1.example.com, static2.example.com) per moltiplicare le connessioniNiente di tutto questo era il protocollo che funzionava come progettato. Era l'intero ecosistema che compensava la limitazione fondamentale di HTTP/1.1.
HTTP/1.1 scalata imbrogliando, non fissando il modello.
HTTP/1.1 lavorato abbastanza bene per quindici anni. Non perché fosse buono, ma perché l'ambiente compensava:
Il protocollo era ancora rotto, siamo stati fortunati che il mondo lo nascondesse.
Quei sei collegamenti per ospite non erano gratuiti:
Il web è diventato più veloce nell'era HTTP/1.1. Ma non a causa di HTTP/1.1. È diventato più veloce perché:
Stavamo costruendo una piattaforma applicativa su un protocollo di recupero documenti, il protocollo stava perdendo, ma non l'abbiamo ancora sentito.
Entro il 2010, le prestazioni web sono state una battaglia costante contro l'HTTP stesso.
Le "migliori pratiche" dell'epoca raccontano la storia:
Ognuno di questi è una soluzione per "HTTP/1.1 non può gestire molte richieste in modo efficiente."
Ho costruito molti di questi piccoli strumenti come generatori di sprite, compressori CSS, abbiamo iniziato a usare la compressione di risposta ecc...
I browser non erano più veloci perché HTTP migliorato. Erano più veloci perché essi lavorato intorno HTTP.
Sei connessioni per host non è una caratteristica. E 'un hack. Domain sharding non è una buona pratica. E 'un'ammissione di fallimento.
Ho passato anni ad insegnare agli sviluppatori a combinare risorse, immagini sprite e risorse critiche in linea. Niente di tutto questo era "buona architettura." controllo dei danni al protocollo.
Il mito "HTTP è semplice" persiste perché la complessità era nascosta in:
HTTP/1.1 ha funzionato perché tutto intorno Ha fatto gli straordinari per compensare.
Se hai mai visto un diagramma di HTTP che non mostra modalità di latenza, perdita o guasto, ti sta mentendo. Il protocollo è semplice. La realtà non lo è.
Nel 2010, il web si era trasformato di nuovo. Due massicci cambi cambiarono tutto:
1. Mobile è accaduto. L'iPhone lanciato nel 2007. Entro 2012, il traffico web mobile stava esplodendo. Improvvisamente gli utenti non erano su banda larga cablata - erano su 3G, poi 4G, con latenza variabile e perdita frequente di pacchetti. Le ipotesi che hanno reso HTTP/1.1 tollerabile stavano rompendo.
2. Le applicazioni Web hanno sostituito le pagine web. Gmail. Google Maps. Facebook. Twitter. Questi non erano documenti con collegamenti. Erano applicazioni che avevano bisogno di decine o centinaia di risorse, aggiornamenti in tempo reale, e risposta immediata. L'hack "sei connessioni per host" stava mostrando la sua età.
Google sentiva questo dolore acutamente. Avevano enormi dimensioni, ingegneri ossessionati dalle prestazioni, e i dati per dimostrare HTTP/1.1 è stato il collo di bottiglia. Nel 2009, hanno iniziato SPDY - un protocollo sperimentale che ha influenzato pesantemente HTTP/2 (non identico, ma la stessa direzione).
Che cosa è cambiato:
┌──────────────────────────────────────────┐
│ Single TCP Connection │
├──────────────────────────────────────────┤
│ Stream 1: GET /page.html │
│ Stream 3: GET /style.css │
│ Stream 5: GET /app.js │
│ Stream 7: GET /logo.png │
│ (all interleaved, no ordering required) │
└──────────────────────────────────────────┘
Questo è ciò che dovrebbe essere il pipelining HTTP/1.1. I flussi sono indipendenti. Una risposta lenta non blocca gli altri. Le intestazioni sono compresse. Il protocollo finalmente corrisponde a come usiamo effettivamente il web.
HTTP/2 è stato perfetto per il web a banda larga. E nel 2015, quando ha standardizzato, la banda larga era onnipresente nel mondo sviluppato.
Cosa è migliorato:
Per gli utenti su connessioni cablate con bassa perdita di pacchetti, HTTP/2 è stato un vero e proprio miglioramento. I benchmark sembrava grande. Le metriche migliorate. Google ha dichiarato la vittoria.
Ma il mondo era già andato avanti. Mobile era ora la maggior parte del traffico web.
E le reti mobili hanno una proprietà fondamentale che la banda larga non: perdita di pacchetti è comune e imprevedibile.
Garanzie TCP Consegna in ordine. Se il pacchetto 47 viene perso, i pacchetti 48-100 aspettano che venga ritrasmessa 47 - anche se appartengono a flussi HTTP/2 completamente indipendenti.
┌──────────────────────────────────────────┐
│ TCP Receive Buffer │
├──────────────────────────────────────────┤
│ [pkt 45][pkt 46][ ? ][pkt 48][pkt 49] │
│ ↑ │
│ Waiting for packet 47 │
│ │
│ Stream 1 data: BLOCKED │
│ Stream 3 data: BLOCKED │
│ Stream 5 data: BLOCKED (has pkt 48-49) │
│ Stream 7 data: BLOCKED │
└──────────────────────────────────────────┘
HTTP/2 ha risolto il blocco head-of-line al livello dell'applicazione. Poi TCP lo ha reintrodotto al livello del trasporto.
Un pacchetto perso blocca tutti i flussi. Su una connessione cablata pulita, la perdita di pacchetti è rara. Su reti mobili, WiFi lossy, o link congestionati? La perdita di pacchetti è costante. E perché HTTP/2 utilizza un single connessione (per disegno), un pacchetto perso ora blocca tutto invece di una sola delle sei connessioni.
Prestazioni HTTP/2:
L'ironia: HTTP/2 è stato pensato per risolvere il problema del multiplexing del web - proprio come il cellulare ha reso impossibile la perdita da ignorare. Le garanzie di TCP hanno peggiorato sul cellulare rispetto al protocollo che ha sostituito.
Le implementazioni iniziali HTTP/2 hanno mostrato reali miglioramenti:
Tutti quegli strumenti che ho costruito per 1.1? Il tutto è andato via con HTTP/2, improvvisamente bundling era una cosa negativa. multiplexing di HTTP/2 è stato grande per le risorse sulla stessa origine, ma non ha aiutato con le richieste di origine incrociata. Abbiamo dovuto costruire nuovi strumenti per impacchettare quelli (webpack su questo sito, per esempio!).
Ma la latenza di coda ha raccontato un'altra storia. mediana Il P99 e' peggiorato.
Ho visto questo in prima persona: un client abilitato HTTP/2 attraverso il loro CDN e guardato cellulare P99 latenza aumento da 40%. I cruscotti hanno mostrato miglioramento sul desktop. I biglietti di supporto provenivano dagli utenti mobili. Abbiamo trascorso una settimana a capire che il "miglioramento" di HTTP/2 stava peggiorando le cose per la maggior parte del loro traffico.
Quando HTTP/2 funziona, funziona splendidamente. Quando un pacchetto cade su una connessione mobile nel momento peggiore, tutto si blocca. E gli utenti notano congela più di quanto notino mediani veloci.
Il problema fondamentale:
HTTP/2 ha ipotizzato che il TCP fosse abbastanza buono.
Per la banda larga, lo era. Per il cellulare, non lo era. E quando HTTP/2 era standardizzato, il cellulare stava già vincendo. Avevamo spinto fino a TCP potrebbe portarci.
Entro il 2015 le prove erano chiare: TCP era il problema.
Google era in esecuzione QUIC sperimentalmente dal 2012. Avevano i dati. Su reti mobili, lossy WiFi, e connessioni ad alta latenza, HTTP/2 su TCP stava fallendo in modi che non potevano essere fissati senza cambiare il livello di trasporto.
Ma non si può solo "fix TCP." È implementato in kernel di sistema operativo. È cotto in ogni router, firewall, e middlebox su Internet. Cambiare TCP significa aspettare decenni per l'intera infrastruttura di Internet per l'aggiornamento.
Così Google ha fatto qualcosa di audace: Hanno costruito un nuovo protocollo di trasporto in cima all'UDP.
UDP è "dumb" dal design - invia solo pacchetti senza garanzie. Ma questo è esattamente ciò di cui avete bisogno se si vuole implementare il tuo affidabilità semantica. QUIC reimplementa le garanzie di TCP (affidabile, consegna ordinata) ma lo fa per flusso invece di per ogni connessione.
HTTP/3 (2022) è HTTP su QUIC. È l'ammissione che dovevamo andare sotto HTTP per correggere HTTP.
Che cosa è cambiato:
┌──────────────────────────────────────────┐
│ QUIC Connection │
├──────────────────────────────────────────┤
│ Stream 1: [pkt][pkt][pkt] ← flowing │
│ Stream 3: [pkt][ ? ][pkt] ← waiting │
│ Stream 5: [pkt][pkt][pkt] ← flowing │
│ Stream 7: [pkt][pkt] ← flowing │
│ │
│ Lost packet only affects Stream 3 │
└──────────────────────────────────────────┘
Quello che rimaneva lo stesso:
HTTP/3 non ha cambiato HTTP. Ha cambiato il modo in cui HTTP sopravvive alla realtà.
QUIC implementa le garanzie di affidabilità di TCP per flussoQuesta e' l'intuizione chiave.
La promessa di TCP: "Ogni byte arriva in ordine." La promessa di QUIC: "Ogni byte in questo flusso arriva in ordine."
Questa distinzione è il motivo per cui HTTP/3 non collassa sulle reti lossy.
Altre caratteristiche QUIC che fissano problemi di lunga data:
Migrazione della connessione:
Phone on WiFi → walks out of range → switches to cellular
TCP: Connection dies. Restart everything.
QUIC: Connection ID maintained. Streams continue.
Questo è importante perché gli utenti mobili costantemente Cambiare rete. Uscire di casa, perdere WiFi, passare al cellulare. Con TCP, ogni connessione muore. Con QUIC, la connessione continua.
Ripresa 0-RTT:
First connection: Full handshake (1-RTT)
Returning user: Send data immediately (0-RTT)
Cifratura ovunque:
TCP + TLS: Handshake, then encrypted tunnel
QUIC: Encryption is the handshake (TLS 1.3 integrated)
HTTP/3 è progettato per il mondo in cui viviamo:
Il protocollo finalmente corrisponde alla realtà della rete. Trent'anni dopo che HTTP/1.0 ha assunto connessioni cablate affidabili, HTTP/3 riconosce che l'affidabilità è l'eccezione, non la regola.
HTTP/3 non è gratuito:
Ma per le applicazioni mobile-first, reti inaffidabili e servizi sensibili alla latenza, HTTP/3 è la prima versione che corrisponde a come le reti si comportano effettivamente.
Ogni cambiamento di versione HTTP è avvenuto perché l'ambiente è cambiato più velocemente del protocollo.
| Versione | Era | Ambiente | Assunzione | Perché si è rotta |
|---|---|---|---|---|
| HTTP/1.0 | 1996 | Dialup, documenti | Bandwidth is the bottleneck | Pages become apps, latenza materiad |
| HTTP/1.1 | 1999-2015 | banda larga, applicazioni web | bassa latenza nasconde inefficienza | Mobile è arrivato con perdita di pacchetto |
| HTTP/2 | 2015-2022 | Picco a banda larga, rialzo mobile | TCP è abbastanza affidabile | Mobile è diventato dominante, TCP fallito |
| HTTP/3 | 2022+ | Mobile-first, global | Nothing is affidable | Still deploying... |
Il modello è chiaro:
Il protocollo continua ad essere spinto più vicino alla rete. Ogni astrazione che sembrava sufficiente è stata rimossa quando l'ambiente lo ha richiesto.
Altre osservazioni:
Ecco la parte scomoda. Nonostante trent'anni di evoluzione del protocollo:
Le richieste continuano a fallire. Partizione di reti. Server crash. I timeout accadono. Il tuo codice ha ancora bisogno di riprovare la logica.
Le reti mentono ancora. 200 OK non significa che la risposta sia corretta. La connessione chiusa non significa che la richiesta non sia riuscita. I timeout non significano che il server non abbia elaborato la tua richiesta.
Le cache servono ancora dati stantii.
Cache-Control è una richiesta, non un comando. I proxy fanno quello che vogliono. La invalidazione CDN è al massimo possibile.
I clienti provano ancora male. Pulsante di clic dell'utente, non succede nulla, fa clic di nuovo. Ora avete due richieste.
Gli sviluppatori hanno ancora frainteso l'idempotenza. GET dovrebbe essere sicuro. PUT dovrebbe essere idempotente. POST è il wild west. La maggior parte delle API sbaglia.
// This is still your problem, regardless of HTTP version
public async Task<Result> CreateOrderAsync(Order order)
{
// What happens if this times out?
// Did the server receive it?
// Did it process it?
// Will the client retry?
// Will you create duplicate orders?
// HTTP/3 doesn't save you here.
// Idempotency keys do.
}
Se non li capisci, HTTP/3 non ti salverà.
Dopo aver creato applicazioni web in tutte queste versioni di protocollo, ecco cosa si è bloccato:
1. Il protocollo non è il vostro livello di affidabilità.
HTTP ti dà la semantica richiesta/risposta. Non garantisce la consegna, la correttezza o l'elaborazione esattamente una volta. Questo è il tuo lavoro.
2. La latenza è il nemico, non la larghezza di banda.
La maggior parte dei problemi di prestazione sono legati a andata e ritorno, non throughput limitato. La riduzione delle richieste conta più di comprimere payload.
3. Ogni "best practice" ha una data di scadenza.
Domain sharding era essenziale per HTTP/1.1. E 'attivamente dannoso per HTTP/2 (rompe il vantaggio di singola connessione). "Bundle everything into one file" è stato gospel; ora la spedizione di molti piccoli moduli su HTTP/2 o HTTP/3 è spesso meglio. La tattica cambia. L'obiettivo (ridurre la latenza) rimane lo stesso.
4. Misurare sulle reti reali.
I parametri di riferimento sul localhost non provano nulla. I tuoi utenti sono su reti mobili, hotel WiFi e connessioni in caffetteria saturi.
5. Le parti noiose contano di più.
Timeout. Ritiri. Interruttori. Idempotenza. Connection pooling. Questi dettagli poco glamour determinano se il sistema funziona sotto carico.
HTTP non è diventato più veloce perché è diventato più intelligente. È diventato più veloce perché abbiamo finalmente ammesso la rete era il problema.
Ogni versione era giusta per il suo tempo:
L'errore è stato quello di pensare che qualcuno di loro fosse una soluzione permanente, che rispondesse a pressioni ambientali specifiche; quando l'ambiente cambiava, il protocollo doveva seguire.
Le versioni HTTP non sono aggiornamenti in senso consumer. Sono compromessi ottimizzati per diverse distribuzioni fallimentari.
E ancora, dopo tutto questo, i fondamenti rimangono:
Il protocollo si e' evoluto, i problemi non sono scomparsi, si sono solo spostati.
Costruire sistemi che sopravvivano a guasti. Testare su reti reali. Capire che ogni versione HTTP è un tradeoff modellato dalla sua epoca, non un upgrade che obsoleto ciò che è venuto prima.
Sono trent'anni di HTTP. Questo è il web che abbiamo costruito. E in un altro decennio, le ipotesi di HTTP/3 saranno probabilmente datate come quelle di HTTP/1.0.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.