由于SSL握手异常,.NET Core 3.0上的WebRequest第二次失败



问题是,如果在程序的同一生存期内运行一次,下面的代码会成功,但如果运行两次,则会失败。

var request = (HttpWebRequest)WebRequest.Create("https://google.com");
var response = (HttpWebResponse)await request.GetResponseAsync();

我有.NET Core 3.0SDK 3.0.100.

复制:

  1. dotnet new console -n test-sslcd test-ssl
  2. 打开Program.cs
  3. 将内容替换为:
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace test_ssl
{
class Program
{
static async Task Main(string[] args)
{
await CallGoogle();
await CallGoogle();
}
private static async Task CallGoogle()
{
var request = (HttpWebRequest)WebRequest.Create("https://google.com");
var response = (HttpWebResponse)await request.GetResponseAsync();
var jsonResponse = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine(jsonResponse);
}
}
}
  1. dotnet run

这将崩溃,出现异常:

Unhandled exception. System.Net.WebException: The SSL connection could not be established, see inner exception. The handshake failed due to an unexpected packet format.
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.IO.IOException: The handshake failed due to an unexpected packet format.
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslStream.ThrowIfExceptional()
at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at System.Net.HttpWebRequest.SendRequest()
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.WebRequest.<>c.<GetResponseAsync>b__68_2(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at test_ssl.Program.CallGoogle() in C:UsersmesourceWorkspacesteststest-sslProgram.cs:line 19
at test_ssl.Program.Main(String[] args) in C:UsersmesourceWorkspacesteststest-sslProgram.cs:line 13
at test_ssl.Program.<Main>(String[] args)

为什么第二次会失败?

这个问题发布在github上的.NET Core中,因为它似乎与此有关:https://github.com/dotnet/core/issues/3847

进一步测试以缩小问题范围

.NET Framework 4.8-工作

不过,使用.NET Framework 4.8控制台应用程序确实有效。因此,使用原始的Program.cs文件可以在这里工作。看起来真正的问题是.NET Core 3.0

Docker中的.NET Core 3.0-正在工作

docker run --rm -it mcr.microsoft.com/dotnet/core/sdk:3.0
dotnet new console -n test-ssl
cd test-ssl
// Replace content of Program.cs again.
dotnet run
// Everything works.

这让我相信我的机器上有东西坏了,也许也不是防火墙问题,因为最终docker容器将通过与我的计算机相同的防火墙到达谷歌。

Powershell测试-工作

测试ssl.ps1

Invoke-WebRequest -Uri 'https://google.com'
Invoke-WebRequest -Uri 'https://google.com'

HttpClient.NET Core 3.0-不工作

使用HttpClient会产生相同的错误。因此,用以下内容替换CallGoogle的内容不起作用:

var client = new HttpClient();
await client.GetStringAsync("https://google.com");

由于系统基本上在其他任何地方都能工作,所以系统一定已经损坏了。有一台正在工作的新电脑。

最新更新