Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2ConnectionErrorException

Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2ConnectionErrorException

我有以下异常

Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2ConnectionErrorException: HTTP/2 connection error (PROTOCOL_ERROR): Invalid HTTP/2 connection preface.

我会描述我的条件。我有非常简单的 grpc .Net Core 项目,我想要制作 HTTP 端点

这里是Startup.cs

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options => options.EnableEndpointRouting = false);
        services.AddGrpc();

        services.AddHttpClient<IAnalyticApiAsker, AnalyticApiAsker>();

        // db context
        services.AddSingleton<IApplicationMongoContext, ApplicationMongoContext>();

        // repos
        services.AddTransient<IWorkspacesRepo, WorkspaceRepo>();
        services.AddTransient<IApplicationRepo, ApplicationRepo>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            // Communication with gRPC endpoints must be made through a gRPC client.
            // To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909
            endpoints.MapGrpcService<ApplicationsService>();
            endpoints.MapGrpcService<WorkspacesService>();
        });

        // I think I have to use this middleware for get http endpoints ability ?? Right? 
        app.UseMvc();
    }
}

和Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

launchSettings.json

{
  "profiles": {
    "Dashboard": {
      "commandName": "Project",
      "launchBrowser": false,
      "applicationUrl": "http://*:50053",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Local"
      }
    }
  }
}

对于端点,我有以下控制器:

public class HealthController : Controller
{ 
    [Route("/healthcheck")]
    [HttpGet]
    public IActionResult Index()
    {
        return Ok(new
        {
            status = "ok",
            description = "works"
        });
    }
}

但是当我从浏览器请求我的应用程序的 URL http://localhost:50053/healthcheck 时,我遇到了这个异常。看起来 Kestrel 仅为 http2 配置。如果是,如何开启 HTTP 处理?

更新

好的,经过一番研究,我明白了以下内容。不可能同时打开两种协议类型处理:grpc(适用于 HTTP 2)和普通 http1。我说得对吗?

我已将 Startapp.cs 修改为:

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureKestrel(options =>
            {
                options.ListenLocalhost(50053, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
                });
            })
            .UseStartup<Startup>();

HttpProtocols.Http1AndHttp2 此 属性 对每种 HTTP 类型(Http1、Http、Http1AndHttp2)都有变体。但它不适用于 GRPC。我认为它的发生是因为是使用 http1 到 GRPC 还是 http2。而且我不知道如何设置它。

所以,listenOptions.Protocols = HttpProtocols.Http1 - 适用于网络, listenOptions.Protocols = HttpProtocols.Http2 - 适用于 GRPC 和 listenOptions.Protocols = HttpProtocols.Http1AndHttp2 - 适用于网络。

更新 2

我不确定它是否回答了,但我已经在以下 Program.cs 修改的帮助下解决了这个任务:

    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureKestrel(options =>
            {
                options.ListenLocalhost(80, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1;
                });

                options.ListenLocalhost(50053, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                });
            })
            .UseStartup<Startup>();
}

现在我可以使用 http1 和 http2 了。但是现在我有一个新问题,它只适用于本地主机。

好的,我已经在以下Program.cs修改的帮助下解决了它:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureKestrel(options =>
            {
                options.ListenAnyIP(80, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1;
                });

                options.ListenAnyIP(50053, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                });
            })
            .UseStartup<Startup>();
}

现在我可以同时使用 GRPC 和 http1,并且允许任何 IP 连接。

我希望它对将 http1 添加到 GRPC 配置项目的人有用。

grpc 需要 tls。

TLS 不仅仅用于保护通信。当端点支持多种协议时,TLS 应用层协议协商 (ALPN) 握手用于协商客户端和服务器之间的连接协议。此协商确定连接是使用 HTTP/1.1 还是 HTTP/2.

https://docs.microsoft.com/en-us/aspnet/core/grpc/aspnetcore?view=aspnetcore-3.1&tabs=visual-studio