这是我的第一个 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
我在公司代理后面遇到了同样的问题并收到此错误消息
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)