Mensagem de erro
Received an unexpected EOF or 0 bytes from the transport stream.
Também aparece como
- System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
O HttpClient o encapsula em “The SSL connection could not be established, see inner exception.” Logs de aplicações .NET Framework costumam mostrar a mesma situação como “Authentication failed because the remote party has closed the transport stream.”
.NET SslStream / HttpClient — IOException: the peer closed the connection during the TLS handshake
O que significa
O lado remoto (ou um equipamento intermediário) fechou a conexão TCP enquanto o SslStream estava no meio do handshake TLS, sem enviar um alerta TLS. O .NET não tem nenhum motivo a informar além do fluxo fechado. Normalmente, o servidor recusou o handshake em silêncio, ou um proxy ou firewall o derrubou.
Por que acontece
O servidor fecha os handshakes que não aceita
comumNenhuma versão do protocolo ou cifra em comum, um nome SNI ausente ou desconhecido, ou um servidor que exige algo que o cliente não ofereceu — sendo que o servidor fecha a conexão em vez de enviar um alerta.
Um proxy ou firewall derruba a conexão
comumRedes que exigem proxy, firewalls com filtragem de TLS e clientes de VPN encerram em silêncio as conexões bloqueadas.
Aplicações .NET Framework que oferecem apenas versões antigas de TLS
ocasionalAplicações que têm como destino o .NET Framework 4.5 ou anterior, sem as configurações de TLS padrão do sistema operacional, podem oferecer apenas TLS 1.0, que servidores modernos rejeitam.
Como corrigir
- 1.
Testar o handshake a partir da mesma máquina
Se o openssl s_client também tiver a conexão cortada, o problema está na rede ou no servidor; se ele funcionar, compare as versões do protocolo e o SNI com os do cliente .NET.
bash # Does a plain TLS handshake from the same host work? openssl s_client -connect api.example.com:443 -servername api.example.com -brief </dev/null openssl s_client -connect api.example.com:443 -servername api.example.com -tls1_2 -brief </dev/null - 2.
Usar o proxy exigido
Configure o proxy no handler (ou por HTTPS_PROXY no Linux) quando a rede não permitir conexões diretas.
csharp // Use the corporate proxy explicitly (HttpClient also honours HTTPS_PROXY / system settings) var handler = new SocketsHttpHandler { Proxy = new WebProxy("http://proxy.example.net:3128"), UseProxy = true }; using var client = new HttpClient(handler); - 3.
.NET Framework: ativar o TLS 1.2
Mude o framework de destino para a versão 4.7 ou posterior, para que o sistema operacional escolha o protocolo, ou, até que isso seja possível, adicione TLS 1.2 a ServicePointManager.SecurityProtocol.
csharp // .NET Framework 4.x apps compiled for old targets may still offer only TLS 1.0: // target 4.7+ (OS defaults) or, as a stop-gap, enable TLS 1.2 explicitly System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;