Table of contents

Can HttpClient (C#) be used with HTTP/2?

Yes, HttpClient in C# fully supports HTTP/2 starting with .NET Core 2.1. HTTP/2 provides significant performance benefits including multiplexing, header compression, and binary framing. However, both client and server must support HTTP/2 for it to work effectively.

Requirements

  • .NET Core 2.1 or later (including .NET 5, 6, 7, 8+)
  • HTTPS connection (HTTP/2 requires TLS in most implementations)
  • Server support for HTTP/2 protocol

Basic HTTP/2 Usage

Method 1: Explicit Version Setting

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var client = new HttpClient();

        var request = new HttpRequestMessage()
        {
            RequestUri = new Uri("https://httpbin.org/get"),
            Method = HttpMethod.Get,
            Version = HttpVersion.Version20 // Force HTTP/2
        };

        try
        {
            var response = await client.SendAsync(request);

            Console.WriteLine($"Protocol: HTTP/{response.Version}");
            Console.WriteLine($"Status: {response.StatusCode}");

            var content = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Response: {content}");
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine($"Request failed: {ex.Message}");
        }
    }
}

Method 2: Configure Default Version

using var client = new HttpClient();
client.DefaultRequestVersion = HttpVersion.Version20;
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;

// All requests will now use HTTP/2
var response = await client.GetAsync("https://httpbin.org/get");
Console.WriteLine($"Protocol: HTTP/{response.Version}");

Version Policies

Control how HttpClient handles HTTP version negotiation:

using var client = new HttpClient();

// Always use exact version, no fallback
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;

// Use requested version or higher
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher;

// Use requested version or lower (allows fallback)
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;

Multiple Concurrent Requests

HTTP/2's multiplexing allows multiple requests over a single connection:

using var client = new HttpClient();
client.DefaultRequestVersion = HttpVersion.Version20;

var tasks = new List<Task<HttpResponseMessage>>();

// Send 10 concurrent requests - HTTP/2 will multiplex them
for (int i = 0; i < 10; i++)
{
    var task = client.GetAsync($"https://httpbin.org/delay/{i}");
    tasks.Add(task);
}

var responses = await Task.WhenAll(tasks);

foreach (var response in responses)
{
    Console.WriteLine($"Status: {response.StatusCode}, Protocol: HTTP/{response.Version}");
    response.Dispose();
}

Checking HTTP/2 Support

Verify if a server supports HTTP/2:

public static async Task<bool> SupportsHttp2(string url)
{
    using var client = new HttpClient();

    var request = new HttpRequestMessage(HttpMethod.Head, url)
    {
        Version = HttpVersion.Version20,
        VersionPolicy = HttpVersionPolicy.RequestVersionExact
    };

    try
    {
        var response = await client.SendAsync(request);
        return response.Version.Major == 2;
    }
    catch
    {
        return false;
    }
}

// Usage
bool supportsHttp2 = await SupportsHttp2("https://google.com");
Console.WriteLine($"Server supports HTTP/2: {supportsHttp2}");

Server Configuration (ASP.NET Core)

Kestrel Configuration

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.ListenAnyIP(5001, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
                    listenOptions.UseHttps();
                });

                // HTTP/2 only (no HTTP/1.1 fallback)
                options.ListenAnyIP(5002, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                    listenOptions.UseHttps();
                });
            });
        });

appsettings.json Configuration

{
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http1AndHttp2"
    },
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:5001",
        "Protocols": "Http1AndHttp2"
      },
      "Http2Only": {
        "Url": "https://localhost:5002",
        "Protocols": "Http2"
      }
    }
  }
}

Performance Considerations

Connection Pooling

HTTP/2 uses fewer connections due to multiplexing:

// Configure connection limits for HTTP/2
var handler = new SocketsHttpHandler()
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(2),
    MaxConnectionsPerServer = 2 // Fewer connections needed with HTTP/2
};

using var client = new HttpClient(handler);
client.DefaultRequestVersion = HttpVersion.Version20;

Stream Limits

Be aware of HTTP/2 stream limits:

// Monitor concurrent streams
var semaphore = new SemaphoreSlim(100, 100); // Limit concurrent requests

var tasks = urls.Select(async url =>
{
    await semaphore.WaitAsync();
    try
    {
        return await client.GetAsync(url);
    }
    finally
    {
        semaphore.Release();
    }
});

Common Issues and Solutions

1. HTTPS Requirement

// HTTP/2 typically requires HTTPS
var handler = new HttpClientHandler()
{
    ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
};

using var client = new HttpClient(handler);

2. Version Fallback Handling

public static async Task<HttpResponseMessage> GetWithFallback(string url)
{
    using var client = new HttpClient();

    // Try HTTP/2 first
    var request = new HttpRequestMessage(HttpMethod.Get, url)
    {
        Version = HttpVersion.Version20,
        VersionPolicy = HttpVersionPolicy.RequestVersionOrLower
    };

    var response = await client.SendAsync(request);

    if (response.Version.Major < 2)
    {
        Console.WriteLine("Fell back to HTTP/1.1");
    }

    return response;
}

Limitations

  • Server Push: Not supported by HttpClient
  • Trailers: Limited support for HTTP/2 trailers
  • Frame Types: Only standard HTTP/2 frames are supported
  • ALPN: Automatic, but limited configuration options

Best Practices

  1. Reuse HttpClient instances to benefit from connection pooling
  2. Use async/await to maximize HTTP/2 multiplexing benefits
  3. Set appropriate timeouts for long-lived connections
  4. Monitor connection health in production environments
  5. Test fallback scenarios when HTTP/2 is unavailable

HTTP/2 support in HttpClient provides significant performance improvements for modern web applications, especially when making multiple concurrent requests to the same server.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon