Definition
- QUIC protocol – a transport built on UDP that combines connection establishment and TLS handshake, typically completing in one round-trip.
- 0-RTT setup – QUIC can resume connections with zero round-trips using cached parameters, versus TCP+TLS which needs three round-trips.
- No head-of-line blocking – HTTP/2 over TCP has one TCP stream; one lost packet stalls ALL HTTP streams. QUIC gives each HTTP stream its own independent transport stream.
- Connection migration – QUIC connections survive IP address changes (WiFi to mobile), unlike TCP which requires a new handshake.
- JDK integration –
HttpClient.Version.HTTP_3requests QUIC, with automatic fallback to HTTP/2.
HTTP/2 over TCP is a single-lane bridge: one accident blocks all traffic. HTTP/3 over QUIC has multiple independent lanes: one accident only blocks that lane. Plus entering the bridge is faster (0-RTT) and you can switch bridges mid-journey without stopping (connection migration).
Understanding the Concepts
What is HTTP/3 in JDK HttpClient?
HTTP/3 support in the JDK HttpClient runs over QUIC, a transport protocol built on UDP rather than TCP.
How is QUIC different from TCP?
| Aspect | TCP (HTTP/2) | QUIC (HTTP/3) |
|---|---|---|
| Transport | TCP (connection-oriented) | UDP (connectionless) |
| Connection setup | 3 round-trips (TCP + TLS) | 1 round-trip (combined) |
| Resumption | Not built-in | 0-RTT with cached params |
| Head-of-line blocking | One lost packet stalls all streams | Each stream independent |
| Connection migration | New handshake on IP change | Survives IP changes |
| Multiplexing | HTTP/2 multiplexing | Stream-level independence |
How do you use HTTP/3 in Java?
package com.bank.client;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class BankApiClient {
private final HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_3) // prefer HTTP/3
.build();
public String getAccountBalance(String accountId) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.nationalbank.in/accounts/" + accountId + "/balance"))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return response.body();
// If server supports HTTP/3: uses QUIC (faster setup, no HOL blocking)
// If not: automatically falls back to HTTP/2 over TCP
}
}
Why does 0-RTT matter for banking?
In microservice architectures, services make many short-lived HTTP calls. Each call's latency includes connection setup time. With TCP+TLS, that is 3 round-trips (roughly 30ms on a 10ms network). With QUIC, that drops to 1 round-trip or even 0-RTT for resumed connections.
For a transfer that calls 5 downstream services, connection setup overhead drops from 150ms to 50ms or less.
Why does no head-of-line blocking matter?
A mobile banking app fetches account summary, recent transactions, and offers in parallel over one connection. With HTTP/2 over TCP, a dropped packet on the transactions stream stalls the summary and offers streams until the packet is retransmitted. With HTTP/3, each stream is independent at the transport layer.
What should a senior engineer know?
- HTTP/3 is a network-efficiency improvement, not an API change. Your request/response code stays the same.
- Evaluate HTTP/3 where connection setup cost and packet loss dominate latency: mobile apps, cross-region calls, high-frequency API calls.
- Keep HTTP/2 fallback for servers that do not speak QUIC.
- QUIC runs on UDP port 443; ensure firewalls allow UDP traffic.
What are common interview follow-up questions?
- Does HTTP/3 change the Java API? (No. Same HttpClient, HttpRequest, HttpResponse. Only the transport changes.)
- When does HTTP/3 NOT help? (On reliable, low-latency networks where TCP overhead is negligible.)
- What is connection migration? (QUIC connections use a connection ID instead of IP:port, so they survive WiFi-to-mobile handoffs.)
Visual Overview
HTTP/2 vs HTTP/3 Connection Setup: HTTP/2 (TCP + TLS): Client ──SYN──────────▶ Server 1 RTT Client ◀─SYN+ACK───── Server Client ──ACK──────────▶ Server 2 RTT (TCP done) Client ──TLS Hello───▶ Server 3 RTT (TLS done) Client ◀─TLS Done──── Server Client ──Request─────▶ Server 4 RTT (first request) HTTP/3 (QUIC): Client ──QUIC+TLS────▶ Server 1 RTT (combined!) Client ◀─Response──── Server Client ──Request─────▶ Server (first request in 1 RTT) Resumption (0-RTT): Client ──Data────────▶ Server 0 RTT (cached params)
Key Takeaway
HTTP/3 in the JDK HttpClient uses the QUIC protocol (UDP-based) for three improvements over HTTP/2. First, 0-RTT connection setup combines transport and TLS handshake in one round-trip instead of three. Second, no head-of-line blocking means one lost packet only affects its stream, not all streams on the connection. Third, connection migration allows connections to survive network changes without re-establishing.
The Java API is unchanged: same HttpClient, HttpRequest, and HttpResponse. You set HttpClient.Version.HTTP_3 and the client negotiates QUIC with the server, falling back to HTTP/2 if unavailable. Application code does not change.
In banking microservices, HTTP/3 reduces inter-service latency (fewer round-trips for connection setup) and improves resilience on unreliable networks (mobile banking apps, cross-region calls). The benefit is most significant when connection setup cost and packet loss are the dominant latency contributors.
Remember one sentence: HTTP/3 uses QUIC for 0-RTT connection setup, no head-of-line blocking, and connection migration, while keeping the same Java HttpClient API.
---