.NET 5 GRPC 客户端调用引发异常:在未启用 HTTP/2 的情况下使用版本策略 RequestVersionOrHigher 请求 HTTP 版本 2.0

Jac*_*cob 10 c# grpc .net-5

这是我的第一个 gRPC 应用程序。我尝试从 .NET 5 gRPC 客户端 (Grpc.Net.Client 2.35.0) 调用服务器流式 RPC 调用,这会在我的本地开发环境中导致以下异常:

Grpc.Core.RpcException:Status(StatusCode =“Internal”,Detail =“启动gRPC调用时出错。HttpRequestException:使用版本策略RequestVersionOrHigher请求HTTP版本2.0,而未启用HTTP/2。”

无论服务器应用程序是否正在运行,都会发生这种情况。这是我用来拨打电话的代码:

using var channel = GrpcChannel.ForAddress(@"http://localhost:5000");
var client = new AlgorithmRunner.AlgorithmRunnerClient(channel);
using var call = client.RunAlgorithm(new RunAlgorithmRequest());

while (await call.ResponseStream.MoveNext())
{

}
Run Code Online (Sandbox Code Playgroud)

我的理解是,.NET 5 gRPC 默认情况下应该启用 HTTP/2:为什么异常表明 HTTP/2 未启用以及如何解决?

Jac*_*cob 14

经过进一步调查,这似乎与我的计算机上与我公司的网络设置相关的代理设置有关。具体来说,我定义了以下环境变量:

http_代理 https_代理

.NET 从这些环境变量填充 HttpClient DefaultProxy。我的公司代理似乎干扰了 HTTP/2(不受支持?),导致 gRPC 无法正常工作。本地开发的解决方法是在进行 gRPC 调用之前手动设置 HttpClient 的默认代理:

HttpClient.DefaultProxy = new WebProxy();
                
using var channel = GrpcChannel.ForAddress(@"http://localhost:5000");
var client = new AlgorithmRunner.AlgorithmRunnerClient(channel);
using var call = client.RunAlgorithm(new RunAlgorithmRequest());
Run Code Online (Sandbox Code Playgroud)

这可能代表通过某些类型的代理使用 gRPC 的普遍问题。

  • 谢谢,雅各布。这解决了我的头痛问题。 (2认同)
  • 在没有代理且使用 https 的 Windows7 上运行的客户端上似乎也会发生相同的错误。似乎 Windows7 不支持使用带有 TLS 的 HTTP/2 的 HttpClient。 (2认同)
  • 我在运行 fiddler 的情况下启动 `Grpc` 客户端和服务时遇到了这个问题,您的答案解决了这个问题。一旦 Fiddler 关闭,就不需要这条线了。我在此测试中根本没有使用“HTTPS”,并且“HTTP2”配置正确。 (2认同)

小智 2

我在公司代理后面遇到了同样的问题并收到此错误消息

An exception of type 'Grpc.Core.RpcException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Status(StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: Connection refused SocketException: Connection refused", DebugException="System.Net.Http.HttpRequestException: Connection refused
Run Code Online (Sandbox Code Playgroud)

我完全同意您建议的通过覆盖DefaultProxy来绕过所有代理设置的解决方法是合法且有效的。

稍微好一点的方法是不要在代码中硬编码“绕过所有代理语句”,而是使用no_proxy环境变量。该环境变量的目的是定义排除发往某些主机的流量的规则

解决方案

激活环境。变量no_proxy适合您的开发设置,例如

对于Linux

export no_proxy=localhost,127.0.0.1
Run Code Online (Sandbox Code Playgroud)

对于 Dockerfile

ENV no_proxy=localhost,127.0.0.1
Run Code Online (Sandbox Code Playgroud)

有关代理环境变量的深入讨论

启动 gRPC 客户端应用程序时,检查读取的环境变量的值非常重要,因为 gRPC在底层使用HttpClient类,该类会考虑所有代理环境变量。如果没有设置no_proxy值,则没有效果。

var noProxy = Environment.GetEnvironmentVariable("no_proxy");
Run Code Online (Sandbox Code Playgroud)