如何通过普通 http 在 C# Kestrel Web 服务器中启用 http2?

jjx*_*tra 6 c# http

我如何(是否有可能)在 C# Kestrel Web 服务器中通过普通 http 启用 http2?所有 Microsoft 文档都表明需要 https/TLS,但我有将在负载平衡器或 nginx 后面运行的服务,因此不需要第二层 https。官方 http2 规范表明不需要 https。

jjx*_*tra 10

使用未加密 http2 的场景是负载均衡器、代理等。

您必须做三件事才能在未加密的通道上使用 http2。

设置 Kestrel 以在您的服务器上使用 http2:

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);
    });
});
Run Code Online (Sandbox Code Playgroud)

对于 .net 5+,创建您的HttpClient实例,然后创建一条消息并指定版本:

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

对于 .net core 3.1 及更早版本,设置一个标志以启用未加密的 http2。然后,当您创建 时HttpClient,请指定版本:

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

如果需要在完全未加密的主机上同时支持 http1 和 http2,则需要侦听两个端口,每个端口对应一个 http 版本。然后您的负载平衡器或代理需要处理 http 版本并定向到适当的端口。

您不会在浏览器上看到 http2,并且可能会出现协议错误,因此在这些情况下,您可以仅将 http1 协议指令用于开发环境。不理想,但它至少可以让您在本地进行测试。


小智 8

确保您使用的是Microsoft.AspNetCore.WebHost而不是通用的,Microsoft.Extensions.Hosting.Host因为在 docker Linux 实例上运行 dotnet core 3 grpc 容器时CreateDefaultBuilder您会遇到烦人的情况OpenSslCryptographicException

另外,如果您正在使用运行状况检查,请务必将其公开在不同的端口上,如下面的代码Program.cs片段所示:

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>();
Run Code Online (Sandbox Code Playgroud)


Jin*_*ter 5

最简单的方法是使用 appSettings.json 中 Kestrel 的配置部分。

  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http2"
    }
  },
Run Code Online (Sandbox Code Playgroud)

要关闭 SSL,您可能需要从 Statup.cs 配置方法中删除app.UseHsts(),选项并仅公开 Http url。app.UseHttpsRedirections()

您还可以同时使用和Http1AndHttp2来支持两者。Http1Http2