具有未加密 HTTP2 连接的 .Net Core 3.1 gRPC 客户端

Kru*_*sty 8 c# .net-core grpc asp.net-core

我正在尝试查询一些在 HTTP 上运行的本地 gRPC 服务。这是我的 net core 3.1 控制台应用程序:

static async Task Main(string[] args)
{
    AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

    using var channel = GrpcChannel.ForAddress("http://localhost:16050");
    var client = new EventService.EventServiceClient(channel);
    var reply1 = await client.GetTrackEventAsync(new GetTrackEventRequest { Name = "01Austra14" });
}
Run Code Online (Sandbox Code Playgroud)

但它抛出了这个错误:

System.Private.CoreLib.dll 中发生“Grpc.Core.RpcException”类型的异常,但未在用户代码中处理:“Status(StatusCode=”Internal”, Detail=”启动 gRPC 调用时出错。HttpRequestException: 发生错误发送请求时。Http2ConnectionException:HTTP/2 服务器在连接上发送了无效数据。HTTP/2 错误代码“PROTOCOL_ERROR”(0x1)。”,DebugException =“System.Net.Http.HttpRequestException:发送时发生错误请求。 ---> System.Net.Http.Http2ConnectionException: HTTP/2 服务器在连接上发送了无效数据。HTTP/2 错误代码“PROTOCOL_ERROR”(0x1)。

不幸的是,目前我们无法添加 SSL 证书,我们需要暂时使用纯 HTTP(服务应用程序尚未投入生产)。有人知道这里发生了什么吗?

根据文档,调用AppContext.SetSwitch应该足够了。

服务器是一个 Asp Net Core 3.1 应用程序。它运行于:

  • 端口 http://*:16050
  • 端口 https://*:16150。这会正确回复客户端,但如上所述,目前只能在本地使用

服务器提供

  • Http1 和 Http2
  • 同一端口上的 REST API 和 gRPC API

客户端正在使用以下包

  <ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.17.0" />
    <PackageReference Include="Grpc.Net.Client" Version="2.37.0" />
    <PackageReference Include="Grpc.Tools" Version="2.37.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 5

我不能 100% 确定这适用于您的场景(尽管“Http1 和 Http2”表明:它将适用),但是:我已经在尝试同时服务 HTTP/ 的非 TLS 端点上看到了此问题1 和 HTTP/2 流量 - 它会有点混乱,并尝试使用 HTTP/1 响应来响应 HTTP/2 请求(这不会发生在 TLS 端点上,因为握手的工作方式不同)。就我而言,修复方法是告诉服务器提供 HTTP/2 服务。这可以在Kestrel/EndPoints节点下的 appSettings.json 中通过指定 来完成"Protocols": "Http2",或者在 Program.cs 中通过listenOptions.Protocols = HttpProtocols.Http2ConfigureKestrel调用中指定来完成。当我想在没有 TLS 的情况下提供 HTTP/1 和 HTTP/2 服务时,我总是不得不使用不同的端口等。