好吧,我对我需要做的事情感到不知所措,我有一个用 .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
我确实看到稍后有一个加密警报,但这种情况是在抛出异常后几秒钟发生的,所以我不确定为什么。
无论哪种方式,我认为它可能是一个自签名证书,所以我添加到 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。任何帮助将不胜感激
事实证明,这毕竟是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
}
希望这对遇到这个愚蠢问题的人也有帮助。