HTTP/2 and HTTP/3 (QUIC): Multiplexing, Header Compression
What This Concept Is
HTTP/2 and HTTP/3 are not replacements for HTTP's request/response model. The methods, status codes, and header names are almost unchanged. What changed is how those messages are framed and carried on the wire.
HTTP/2:
- runs over one TCP connection, but multiplexes many concurrent streams
- uses a binary framing layer instead of ASCII text
- compresses headers with HPACK (static + dynamic tables, Huffman coding)
- supports server push (rarely used in practice now)
HTTP/3:
- runs over QUIC, which runs over UDP (not TCP)
- moves reliability, ordering, and congestion control into the user-space QUIC implementation
- integrates TLS 1.3 into the transport handshake (one or zero RTT)
- fixes HTTP/2's remaining head-of-line blocking by giving each stream its own independent delivery
Why It Matters Here
HTTP/1.1's head-of-line blocking was painful: one slow response on a keep-alive connection blocked everything behind it. Browsers worked around it by opening many parallel TCP connections (wasteful).
HTTP/2 fixes this at the HTTP layer but a single TCP loss still stalls every HTTP/2 stream riding that TCP connection. HTTP/3 fixes that by putting each stream in its own QUIC-level reliability domain.
This is why QUIC is on UDP -- the kernel's TCP could not be extended fast enough, and putting transport in userspace made experimentation possible.
Concrete Example
An HTTP/2 GET / might be carried in a single HEADERS frame on stream 3:
+-----------------------------------------------+
| Length (24) | length of this frame's payload
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) | which stream
+=+=============================================================+
| Frame Payload ... | HPACK-compressed headers
+---------------------------------------------------------------+
Stream IDs let the client and server interleave frames from different requests on one TCP connection. HPACK avoids re-sending the same User-Agent string on every request by indexing it into a dynamic table.
Under HTTP/3, the same logical request rides a QUIC stream; the wire frames are QUIC packets instead of TCP segments, and the TLS 1.3 handshake is woven into the connection setup.
Common Confusion / Misconception
"HTTP/2 is always faster than HTTP/1.1." Not always. For single-request workloads on a reliable network, HTTP/1.1 with keep-alive is competitive. HTTP/2 wins when many requests share a connection and when header sizes matter.
"HTTP/3 is TCP over UDP." No. QUIC is a new transport that happens to use UDP as a substrate. It is not reimplementing TCP; it makes different tradeoffs (per-stream reliability, built-in encryption, faster handshake).
How To Use It
When choosing or debugging:
- If you control client and server and want low-latency APIs, accept either HTTP/2 or HTTP/3 and let ALPN negotiate.
- If a request is stalling, check whether a prior TCP loss is blocking it (
ss -tishows retransmits). On HTTP/3 that should not happen across streams. - Do not optimize HTTP/2 by opening multiple connections -- that defeats header-table reuse and congestion pooling.
Check Yourself
- What is the specific head-of-line blocking that HTTP/2 fixes, and what head-of-line blocking remains on TCP?
- Why does HTTP/3 need to run on UDP rather than TCP?
- Why does HPACK help real workloads even though each header is already just a few dozen bytes?
- What is ALPN and where in the stack is it negotiated?
- If HTTP/2 is already widely deployed, what specific workloads most benefit from moving to HTTP/3?
What Did Not Change
It is worth remembering what these new versions do not change:
- Methods (
GET,POST, etc.) and their semantics are unchanged. - Status codes and their classes are unchanged.
- Header names are unchanged; only the encoding is compressed.
- URI and caching semantics are unchanged.
Practically, an HTTP/1.1 handler in your application layer usually works unchanged on HTTP/2 or HTTP/3 because the framing happens below the level your code sees. That was a deliberate design choice to make the upgrade path tractable for the web ecosystem.
Mini Drill or Application
- Run
curl --http2 -sI https://www.google.com/andcurl --http3 -sI https://www.google.com/(if your curl has HTTP/3). Note the reported ALPN protocol. - Capture both with
tcpdump port 443and compare the number of packets needed for the first response. - Write one paragraph distinguishing what changed in the transport vs what is the same HTTP request semantically.