Yes NET using HTTP/3(QUIC)

Posted by malam on Wed, 26 Jan 2022 17:20:27 +0100

introduce

I told you about using GitHub Actions to do CI/CD before. Today I saw a good article to translate

Source Author link: https://www.meziantou.net/using-http-3-quic-in-dotnet.htm

text

What is HTTP/3

HTTP/3 is a new version of HTTP. Most modern browsers and servers support HTTP/3 protocol. This update should primarily bring performance benefits to mobile users or unreliable connections. The main idea is to replace TCP with a new protocol QUIC, which eliminates some problems of TCP for HTTP. Therefore, QUIC has the following advantages (not an exhaustive list):

  • Establish connections faster by combining TCP and TLS handshakes
  • Reduce thread head blocking by better handling packet loss recovery logic
  • Connection migration, so you don't need to reconnect (shake hands) when moving between networks (e.g. WIFI to cell)

If you want to know more about HTTP/3, you can read the following articles:

. NET 6 supports HTTP/3 for clients (HttpClient including gRPC) and servers (Kestrel). This implementation is based on MsQuic and is a Microsoft implementation of IETF QUIC protocol. Please note that in NET 6 is still in the preview state, so you need to explicitly enable it in csproj or code. At present NET supports HTTP/3:

  • Windows 11 and Windows Server 2022
  • Linux (you may need apt install lib msquic)
  • msquic supports Mac OS using OpenSSL, but NET implementation does not support it at present. In fact NET team prefers to rely on the operating system security API rather than adding new dependencies, such as SecureTransport and macOS. This avoids integration issues, such as certificate management. However, SecureTransport does not disclose the method of implementing QUIC.
Server (Kestrel)

You first need to enable the preview function in csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <EnablePreviewFeatures>true</EnablePreviewFeatures>
  </PropertyGroup>
</Project>

You can then configure Kestrel to listen to HTTP/1, HTTP/2, and HTTP/3. Supporting the old protocol is important because not all clients support the new protocol. In addition, HTTP/3 requires a secure connection, so you must use UseHttps

using Microsoft.AspNetCore.Server.Kestrel.Core;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, options) =>
{
    options.ListenAnyIP(5001, listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
        listenOptions.UseHttps();
    });
});
var app = builder.Build();

app.MapGet("/", () => "hello world");
app.Run();

Most browsers do not allow HTTP/3 for localhost addresses. However, you can verify that the response header is valid by looking at it. The response should contain an alt SVC header with a value h3:

You can also check that the server uses HTTP/3 by enabling more detailed logging. appsettings.json you can change the configuration Appsettings in or Development. json:

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.Hosting.Diagnostics":  "Information"
    }
  }
}

Then you should see the following in the log:

You can also use W3C logging to record and check the protocol version used by the client:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddW3CLogging(logging =>
{
    logging.LoggingFields = W3CLoggingFields.All;
    logging.LogDirectory = @"C:\logs";
    logging.FlushInterval = TimeSpan.FromSeconds(2);
});

builder.WebHost.ConfigureKestrel((context, options) =>
{
    ...
});

var app = builder.Build();
app.UseW3CLogging();
app.MapGet("/", () => "hello world");
app.Run();

Client (HttpClient)

There are two ways to enable HTTP/3 support for HttpClient:

  • Edit csproj to add runtime options
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support"
                                    Value="true" />
  </ItemGroup>
</Project>
  • Set the following switch HttpClient before creating the first one
    System.AppContext.SetSwitch("System.Net.SocketsHttpHandler.Http3Support", true);

You can then use HttpClient to make a request to the HTTP/3 server:

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

// The client falls back to HTTP2 or HTTP1 if HTTP3 is not supported
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;

// Will use HTTP3 if the server supports it
var data = await client.GetStringAsync("https://localhost:5001/");

You can also enable HTTP3 for specific requests:

using var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:5001/");
request.Version = HttpVersion.Version30;
request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

using var response = await client.SendAsync(request);
var data = await response.Content.ReadAsStringAsync();

epilogue

Contact author: Jia Qun: 867095512 @ mrchujiu