.Net 8 Grpc 客户端无法建立 http/2 连接异常:

问题描述 投票:0回答:1

好吧,我对我需要做的事情感到不知所措,我有一个用 .net 8 编写的 WPF 客户端,它应该连接到 Go gRPC 服务器,但每次我尝试连接时,我都会我收到以下异常

 [ALERT] Connection Status: Connection error: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: Requesting HTTP version 2.0 with version policy RequestVersionOrHigher while unable to establish HTTP/2 connection.", DebugException="System.Net.Http.HttpRequestException: Requesting HTTP version 2.0 with version policy RequestVersionOrHigher while unable to establish HTTP/2 connection.")

问题是,当我连接 shark 时,我可以清楚地看到 TLS 1.2 握手已完成并且正在使用 HTTP2

ALPN2

我确实看到稍后有一个加密警报,但这种情况是在抛出异常后几秒钟发生的,所以我不确定为什么。

无论哪种方式,我认为它可能是一个自签名证书,所以我添加到 mainwindow()

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

并采取良好措施以防万一

AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);

我的初始化通道函数看起来像

        internal async Task InitializeChannel(string ip)
        {
            Console.WriteLine("Initializing Channel with IP: " + ip);
            Logger.Log("Initializing Channel with IP: " + ip, 1);

            if (!string.IsNullOrEmpty(ip))
            {
                var parts = ip.Split(':');
                if (parts.Length == 2 && int.TryParse(parts[1], out int port))
                {
                    try
                    {

                        
                        var httpClientHandler = new HttpClientHandler
                        {
                            ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
                            {
                                return true; 
                            },
                            SslProtocols = System.Security.Authentication.SslProtocols.Tls12
                            
                        };


                        var loggingHandler = new LoggingHandler(httpClientHandler);

                        
                        var httpClient = new HttpClient(loggingHandler)
                        {
                            DefaultRequestVersion =  HttpVersion.Version20,
                            DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher
                        };

                        Logger.Log("Creating GrpcChannel", 0);

                        // Create the GrpcChannel using the HttpClient
                        Channel = GrpcChannel.ForAddress($"https://{parts[0]}:{port}", new GrpcChannelOptions
                        {
                            HttpClient = httpClient
                        });


                    }
                    catch (Exception ex)
                    {
                        Logger.Log($"Exception in InitializeChannel: {ex.Message}", 3);
                        throw;
                    }
                }
                else
                {
                    TeamServerStatus = "Invalid IP format";
                    Logger.Log("Invalid IP format", 2);
                }
            }
            else
            {
                Logger.Log("IP is null or empty", 2);
            }
        }

        // Define the custom HttpMessageHandler with logging
        public class LoggingHandler : DelegatingHandler
        {
            public LoggingHandler(HttpMessageHandler innerHandler)
                : base(innerHandler)
            {
            }

            protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                // Log the request details
                Logger.Log($"Request: {request.Method} {request.RequestUri}", 0);
                Logger.Log($"Request Headers: {request.Headers}", 0);
                Logger.Log($"Request Version: {request.Version}", 0);

                // Send the request
                var response = await base.SendAsync(request, cancellationToken);

                // Log the response details
                Logger.Log($"Response: {response.StatusCode}", 0);
                Logger.Log($"Response Headers: {response.Headers}", 0);
                Logger.Log($"Response Version: {response.Version}", 0);

                return response;
            }
        }

这是我尝试连接时生成的日志

[06/24 08:54] [Debug] TS Connect initatied
[06/24 08:54] [Debug] Attempted to connect to TS
[06/24 08:54] [Info] Initializing Channel with IP: 127.0.0.1:5001
[06/24 08:54] [Debug] Creating GrpcChannel
[06/24 08:54] [Info] Attempting to connect to Team Server at: 127.0.0.1:5001
[06/24 08:54] [Debug] Request: POST https://127.0.0.1:5001/App.Auth/ConnectToTeamServer
[06/24 08:54] [Debug] Request Headers: User-Agent: grpc-dotnet/2.59.0 (.NET 8.0.0; CLR 8.0.0; net8.0; windows; x64)
TE: trailers
grpc-accept-encoding: identity,gzip,deflate

[06/24 08:54] [Debug] Request Version: 2.0
[06/24 08:54] [Critical] Connection error: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: Requesting HTTP version 2.0 with version policy RequestVersionOrHigher while unable to establish HTTP/2 connection.", DebugException="System.Net.Http.HttpRequestException: Requesting HTTP version 2.0 with version policy RequestVersionOrHigher while unable to establish HTTP/2 connection.")
[06/24 08:54] [Debug] Connection Status recived: Connection error: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: Requesting HTTP version 2.0 with version policy RequestVersionOrHigher while unable to establish HTTP/2 connection.", DebugException="System.Net.Http.HttpRequestException: Requesting HTTP version 2.0 with version policy RequestVersionOrHigher while unable to establish HTTP/2 connection."

据我所知,它实际上不是http2?但这没有意义,因为它有 ALPN。任何帮助将不胜感激

grpc .net-8.0
1个回答
0
投票

事实证明,这毕竟是Go方。经过大量研究后发现,默认情况下服务器不会通告 ALPN,因此它在协商阶段失败,尽管已硬配置为使用 HTTP2。因此,出现的情况是 .Net 客户端正在发送带有 h2 ALPN 扩展名的 ClienttHello,但 GO 服务器的 ServerHello 并未在响应中包含其 ALPN。由于在这方面协商失败,gRPC 会返回一个错误,无法通过 Http2 建立连接。这与证书不被接受时发生的情况非常相似,这就是为什么我认为它是基于证书的,但我们可以看到来自 Wireshark 的证书是有效的,因为它通过了 TLS 检查,所以其他东西失败了。

TL;DR 修复操作是您必须强制 Go 服务器的 TLS 配置在构建中包含“h2”的 ALPN,如下所示

    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{
            cert,
        },
        NextProtos: []string{"h2"},
    }
return tlsConfig, nil
}

希望这对遇到这个愚蠢问题的人也有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.