连接到不安全的gRPC通道时,“响应过早结束”

时间:2019-09-22 19:09:58

标签: c# .net .net-core grpc

我正在尝试与不安全的gRPC服务器建立连接。我正在使用gRPC在Docker容器内的两个进程之间进行通信,这就是为什么我不需要任何加密或强身份验证的原因。

服务器的行为符合预期,我可以像这样使用grpcurl进行呼叫:

grpcurl -plaintext localhost:42652 SomeService.DoSomething

现在,我正在尝试从.Net Core应用程序中调用相同的RPC方法:

// Registration of the DI service
services.AddGrpcClient<DaemonService.DaemonServiceClient>(options => {
    // Enable support for unencrypted HTTP2
    AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

    options.Address = new Uri("http://localhost:42652");

    // Just a test, doesn't change anything.
    options.ChannelOptionsActions.Add(channelOptions => channelOptions.Credentials = ChannelCredentials.Insecure);
});

// Call
var reply = _someServiceClient.DoSomething(new Request());

但是最后一行的调用会导致异常:

fail: Grpc.Net.Client.Internal.GrpcCall[6]
      Error starting gRPC call.
System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync()
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Grpc.Net.Client.Internal.GrpcCall`2.SendAsync(HttpRequestMessage request)
fail: Grpc.Net.Client.Internal.GrpcCall[3]
      Call failed with gRPC error status. Status code: 'Cancelled', Message: 'Error starting gRPC call.'.
fail: SomeNamespace.Session.Program[0]
      An error occured.
System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync()
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Grpc.Net.Client.Internal.GrpcCall`2.SendAsync(HttpRequestMessage request)
   at Grpc.Net.Client.Internal.GrpcCall`2.GetResponseAsync()
   at Grpc.Net.Client.Internal.HttpClientCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request)
   at Grpc.Core.Interceptors.InterceptingCallInvoker.<BlockingUnaryCall>b__3_0[TRequest,TResponse](TRequest req, ClientInterceptorContext`2 ctx)
   at Grpc.Core.ClientBase.ClientBaseConfiguration.ClientBaseConfigurationInterceptor.BlockingUnaryCall[TRequest,TResponse](TRequest request, ClientInterceptorContext`2 context, BlockingUnaryCallContinuation`2 continuation)
   at Grpc.Core.Interceptors.InterceptingCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request)
   at SomeNamespace.RpcServices.DaemonService.DaemonServiceClient.GetVncContainerEnvironment(EmptyRequest request, CallOptions options) in /src/SomeNamespace.RpcServices/obj/Release/netcoreapp3.0/Vnc-container-daemonGrpc.cs:line 98
   at SomeNamespace.RpcServices.DaemonService.DaemonServiceClient.GetVncContainerEnvironment(EmptyRequest request, Metadata headers, Nullable`1 deadline, CancellationToken cancellationToken) in /src/SomeNamespace.RpcServices/obj/Release/netcoreapp3.0/Vnc-container-daemonGrpc.cs:line 94
   at SomeNamespace.Rpc.RpcEventListener.StartListening() in /src/SomeNamespace/Rpc/RpcEventListener.cs:line 32

您知道我必须做些什么吗?我找不到很多有关建立不安全连接的文档。

1 个答案:

答案 0 :(得分:4)

我自己找到了解决方法:

当我将AppContext.SetSwitch移到AddGrpcClient上方时,它起作用。

// Enable support for unencrypted HTTP2  
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

// Registration of the DI service
services.AddGrpcClient<DaemonService.DaemonServiceClient>(options => {
    options.Address = new Uri("http://localhost:42652");
    options.ChannelOptionsActions.Add(channelOptions => channelOptions.Credentials = ChannelCredentials.Insecure);
});