简体   繁体   中英

How do I enable http2 in C# Kestrel web server over plain http?

How do I (and is it possible) to enable http2 over plain http in the C# Kestrel web server? All Microsoft documentation indicates that https/TLS is required, but I have services that will be running behind a load-balancer or nginx and as such don't need a second layer of https. The official http2 spec indicates that https is not required.

Scenarios to use unencrypted http2 are load balancers, proxies, etc.

You must do three things to use http2 over unencrypted channel.

Setup Kestrel to use http2 on your server:

builder.ConfigureWebHostDefaults((webBuilder) =>
{
    // this will keep your other end points settings such as --urls parameter
    webBuilder.ConfigureKestrel((options) =>
    {
        // trying to use Http1AndHttp2 causes http2 connections to fail with invalid protocol error
        // according to Microsoft dual http version mode not supported in unencrypted scenario: https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0
        options.ConfigureEndpointDefaults(lo => lo.Protocols = HttpProtocols.Http2);
    });
});

For .net 5+, create your HttpClient instance, then create a message and specify the version:

var request = new HttpRequestMessage(HttpMethod.Get, uri)
{
    Version = HttpVersion.Version20,
    VersionPolicy = HttpVersionPolicy.RequestVersionOrHigher
};

For .net core 3.1 and older, set a flag to enable http2 unencrypted. Then, when you create an HttpClient , specify the version:

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var client = new HttpClient { BaseAddress = new Uri(baseUrl), DefaultRequestVersion = new Version(2, 0) };

If you need to support both http1 and http2 on a completely unencrypted host, then you will need to listen on two ports, one for each http version. Then your load balancer or proxy would need to handle the http version and direct to the appropriate port.

You won't see http2 on your browser and will likely get a protocol error, so in those cases you can use an http1 protocol directive just for development environment. Not ideal, but it at least lets you test locally.

Make sure you are using Microsoft.AspNetCore.WebHost instead of the generic Microsoft.Extensions.Hosting.Host for the CreateDefaultBuilder as you will run into an annoying OpenSslCryptographicException when running dotnet core 3 grpc containers on docker linux instances.

Also, if you are using health checks, be sure to expose it on a different port as illustrated in the below Program.cs snippet:

public static IWebHostBuilder CreateHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureKestrel(options => {
            //grpc port for http2 connections
            options.ListenAnyIP(xxxx, listenOptions => {
                listenOptions.Protocols = HttpProtocols.Http2;
            });
            //add health check on a separate port instead of Http1AndHttp2 on same port
            options.ListenAnyIP(xxxx, listenOptions => {
                listenOptions.Protocols = HttpProtocols.Http1;
            });
        })
        .UseStartup<Startup>();

The easiest way is to use configuration section for Kestrel in appSettings.json.

  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http2"
    }
  },

To turn of SSL, you may want to remove app.UseHsts() , app.UseHttpsRedirections() options from Statup.cs Configure method and expose only Http url.

You can also use Http1AndHttp2 to support both Http1 and Http2 together.

In dotnet 5 AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); is no longer supported.

To allow prior knowledge http/2 you need to configure your HttpRequestMessage:

var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost/something"))
            {
                Version = HttpVersion.Version20,
                VersionPolicy = HttpVersionPolicy.RequestVersionOrHigher //This allows http/2 unencrypted,
            };

For reference: https://github.com/dotnet/runtime/issues/987

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM