Сообщение об ошибке
The SSL connection could not be established, see inner exception.
Также выводится как
- System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
Текст не меняется от .NET Core 3.x до .NET 10. Фреймворки (Refit, gRPC, Azure SDK) могут обернуть его ещё раз, поэтому внутреннее исключение может оказаться на два-три уровня глубже.
.NET HttpClient — HttpRequestException wrapping the AuthenticationException or IOException of the TLS handshake
Что это означает
Общая обёртка HttpClient для любого сбоя TLS при подключении. Само сообщение ничего не диагностирует: настоящая причина — в InnerException (исключение AuthenticationException с описанием проблемы с сертификатом или IOException от транспортного уровня). Если записывать в лог только e.Message, причина теряется; записывайте всю цепочку исключений.
Почему это происходит
Проверка сертификата не пройдена
частоНедоверенные или неполные цепочки, просроченные сертификаты или несовпадение имени хоста: внутреннее исключение AuthenticationException называет значение X509ChainStatus или SslPolicyErrors.
Нет общего протокола или шифра
иногдаСтарые серверы на TLS 1.0/1.1 или с устаревшими наборами шифров; в Linux внутренние исключения показывают причину от OpenSSL.
Соединение не по TLS или оборвалось
иногдаПорты с обычным HTTP, прокси или межсетевые экраны, которые закрывают соединение, или серверы, которые сбрасывают рукопожатие.
Как исправить
- 1.
Записывайте в лог всю цепочку исключений
Пройдите по InnerException (или запишите в лог сам объект исключения, а не только Message), чтобы увидеть настоящую причину.
csharp catch (HttpRequestException e) { for (Exception? ex = e; ex != null; ex = ex.InnerException) logger.LogError("{Type}: {Message}", ex.GetType().FullName, ex.Message); } - 2.
Сопоставьте внутреннее сообщение с причиной
Каждое внутреннее сообщение указывает на своё решение; связанные страницы ниже разбирают их по одному.
text Inner exception -> look at "...errors in the certificate chain: UntrustedRoot / PartialChain" -> trust store, server chain "...errors in the certificate chain: NotTimeValid" -> dates, clock "...validation procedure: RemoteCertificateNameMismatch" -> host name vs SAN "Cannot determine the frame size or a corrupted frame was received." -> port is not TLS "Received an unexpected EOF or 0 bytes from the transport stream." -> server/proxy closed "SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL." -> protocol/cipher (Linux)
Связанные ошибки
The remote certificate is invalid because of errors in the certificate chain: U….NET SslStream / HttpClientThe remote certificate is invalid according to the validation procedure: Remote….NET SslStream / HttpClientCannot determine the frame size or a corrupted frame was received..NET SslStream / HttpClientReceived an unexpected EOF or 0 bytes from the transport stream..NET SslStream / HttpClientSSL Handshake failed with OpenSSL error - SSL_ERROR_SSL..NET on Linux (SslStream over OpenSSL)