Hey performance-minded developers! π
Are you still using HTTP/1.1 without realizing it? Let’s unlock the modern protocols that can dramatically improve your app’s network performance!
Quick Protocol Comparison
Feature HTTP/1.1 HTTP/2 HTTP/3 Multiplexing β β β Header Compression β β (HPACK) β (QPACK) Connection TCP TCP QUIC/UDP Head-of-line Blocking β Partial β 0-RTT β β βπ Fun Fact: HTTP/3 uses QUIC, a protocol developed by Google that runs over UDP. It can establish connections up to 3x faster than TCP+TLS because it combines the transport and security handshakes into one round-trip!
Enabling HTTP/2
HTTP/2 is supported since .NET Core 3.0. Enable it:
var handler = new SocketsHttpHandler
{
// Enable HTTP/2 explicitly
EnableMultipleHttp2Connections = true
};
var client = new HttpClient(handler);
Enter fullscreen mode Exit fullscreen mode
With HttpClientFactory
services.AddHttpClient<IMyApiClient, MyApiClient>()
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
EnableMultipleHttp2Connections = true
});
Enter fullscreen mode Exit fullscreen mode
Force HTTP/2
By default, HttpClient negotiates the protocol via ALPN. To force HTTP/2:
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/data")
{
Version = HttpVersion.Version20,
VersionPolicy = HttpVersionPolicy.RequestVersionExact
};
var response = await client.SendAsync(request);
Console.WriteLine($"Protocol: {response.Version}"); // 2.0
Enter fullscreen mode Exit fullscreen mode
Client-Level Default
var client = new HttpClient()
{
DefaultRequestVersion = HttpVersion.Version20,
DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower
};
Enter fullscreen mode Exit fullscreen mode
Enabling HTTP/3
HTTP/3 support came in .NET 6 (preview) and .NET 7 (stable).
// .NET 7+
var client = new HttpClient()
{
DefaultRequestVersion = HttpVersion.Version30,
DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower
};
Enter fullscreen mode Exit fullscreen mode
Per-Request HTTP/3
var request = new HttpRequestMessage(HttpMethod.Get, "https://cloudflare.com")
{
Version = HttpVersion.Version30,
VersionPolicy = HttpVersionPolicy.RequestVersionOrHigher
};
var response = await client.SendAsync(request);
Console.WriteLine($"Protocol: HTTP/{response.Version}"); // Might be 3.0!
Enter fullscreen mode Exit fullscreen mode
Check Server Support
public static async Task<string> GetBestProtocolAsync(HttpClient client, string url)
{
// Try HTTP/3 first
try
{
var request = new HttpRequestMessage(HttpMethod.Head, url)
{
Version = HttpVersion.Version30,
VersionPolicy = HttpVersionPolicy.RequestVersionExact
};
var response = await client.SendAsync(request);
return $"HTTP/{response.Version}";
}
catch (HttpRequestException)
{
// Fall back to HTTP/2
}
try
{
var request = new HttpRequestMessage(HttpMethod.Head, url)
{
Version = HttpVersion.Version20,
VersionPolicy = HttpVersionPolicy.RequestVersionExact
};
var response = await client.SendAsync(request);
return $"HTTP/{response.Version}";
}
catch
{
return "HTTP/1.1";
}
}
Enter fullscreen mode Exit fullscreen mode
Why HTTP/2 is Faster
Multiplexing
HTTP/1.1 can only process one request per connection at a time. To get parallelism, browsers open 6+ connections per domain.
HTTP/2 multiplexes unlimited requests over a single connection:
// These all share ONE TCP connection with HTTP/2
var tasks = new[]
{
client.GetAsync("/api/users"),
client.GetAsync("/api/products"),
client.GetAsync("/api/orders"),
client.GetAsync("/api/settings"),
client.GetAsync("/api/notifications")
};
await Task.WhenAll(tasks);
// Much faster than sequential HTTP/1.1!
Enter fullscreen mode Exit fullscreen mode
Header Compression
HTTP headers are verbose and repetitive. HTTP/2 uses HPACK compression:
HTTP/1.1 headers per request: ~800 bytes
HTTP/2 after compression: ~20-50 bytes (after first request)
Enter fullscreen mode Exit fullscreen mode
That’s 95% smaller headers!
π‘ Pro Tip: Multiple HTTP/2 Connections
Sometimes you want multiple HTTP/2 connections (different auth contexts, load balancing):
var handler = new SocketsHttpHandler
{
EnableMultipleHttp2Connections = true,
MaxConnectionsPerServer = 10 // Allow up to 10 HTTP/2 connections
};
Enter fullscreen mode Exit fullscreen mode
Performance Tuning
Connection Pooling
var handler = new SocketsHttpHandler
{
// HTTP/2 settings
EnableMultipleHttp2Connections = true,
InitialHttp2StreamWindowSize = 65536 * 16, // 1MB window
// Connection lifetime
PooledConnectionLifetime = TimeSpan.FromMinutes(15),
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2),
// Keep connections warm
KeepAlivePingPolicy = HttpKeepAlivePingPolicy.WithActiveRequests,
KeepAlivePingDelay = TimeSpan.FromSeconds(60),
KeepAlivePingTimeout = TimeSpan.FromSeconds(30)
};
Enter fullscreen mode Exit fullscreen mode
GRPC (Built on HTTP/2)
If you’re using gRPC, you’re already on HTTP/2:
var channel = GrpcChannel.ForAddress("https://api.example.com", new GrpcChannelOptions
{
HttpHandler = new SocketsHttpHandler
{
EnableMultipleHttp2Connections = true,
KeepAlivePingDelay = TimeSpan.FromSeconds(60),
KeepAlivePingTimeout = TimeSpan.FromSeconds(30)
}
});
Enter fullscreen mode Exit fullscreen mode
Debugging Protocol Version
public class ProtocolLoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
Console.WriteLine($"β Request version: HTTP/{request.Version}");
var response = await base.SendAsync(request, cancellationToken);
Console.WriteLine($"β Response version: HTTP/{response.Version}");
return response;
}
}
Enter fullscreen mode Exit fullscreen mode
Real-World Impact
I ran a benchmark fetching 100 resources from an API:
Protocol Time Connections HTTP/1.1 4.2s 6 HTTP/2 1.1s 1 HTTP/3 0.9s 1HTTP/2 was 4x faster with 6x fewer connections!
When to Use What
Protocol Best For HTTP/1.1 Legacy systems, simple requests HTTP/2 Most modern APIs, microservices, gRPC HTTP/3 Mobile apps, high-latency networks, CDNsWrapping Up
Upgrading to HTTP/2 is usually a one-liner change that can significantly improve performance β especially for apps making many parallel requests to the same host.
HTTP/3 is the future, with even better performance on unreliable networks. Start testing it now!
Check your protocol version with response.Version and make sure you’re not leaving performance on the table.
Happy speeding! π