.Net 核心 HttpClient 错误?SocketException: 一个现有的连接被远程主机强行关闭 [英] .Net core HttpClient bug? SocketException: An existing connection was forcibly closed by the remote host
问题描述
以下代码在完整的 .Net 框架控制台程序中运行时没有任何错误.但是,在 .Net core 2.1 中运行时出现以下错误.
<前>System.AggregateExceptionHResult=0x80131500Message=发生一个或多个错误.源 = System.Private.CoreLib堆栈跟踪:在 System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)在 C:source eposConsoleApp1Program.cs:line 38 中的 ConsoleApp1.Program.requestString(String url)在 C:source eposConsoleApp1Program.cs:line 13 中的 ConsoleApp1.Program.Main(String[] args)内部异常 1:HttpRequestException: 无法建立 SSL 连接,请参阅内部异常.内部异常 2:IOException:无法从传输连接读取数据:远程主机强制关闭现有连接.内部异常 3:SocketException: 一个现有的连接被远程主机强行关闭代码:
class 程序{静态无效主(字符串 [] args){var url = "https://google.com";var (statusCode, html) = requestString(url);Console.WriteLine("%d %s", statusCode, html);}静态 CookieContainer cc = 新 CookieContainer();静态 HttpClientHandler 处理程序 = 新 HttpClientHandler { AllowAutoRedirect = false, CookieContainer = cc };公共静态异步任务<(int statusCode, string content)>requestStringAsync(字符串网址){ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) =>真的;ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |安全协议类型.Tls11 |SecurityProtocolType.Tls12;//|SecurityProtocolType.Ssl3;使用 (var request = new HttpRequestMessage { RequestUri = new Uri(url), Method = HttpMethod.Get })使用 (var client = new HttpClient(handler)){var response = await client.SendAsync(request);//错误(实际行)//response.EnsureSuccessStatusCode() |>忽略var statusCode = (int)response.StatusCode;var content = await response.Content.ReadAsStringAsync();返回(状态码,内容);}}public static (int statusCode, string content) requestString(string url){返回 requestStringAsync(url).Result;}}
有一个bug 对于 .NET Core 2.1 Preview 提到了这个问题.这可能是原因.但是,我也注意到您的 TLS 设置不正确.您当前正在启用它,但会覆盖已设置的所有其他协议.而不是这样:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |安全协议类型.Tls11 |SecurityProtocolType.Tls12;
你应该使用这个:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls |安全协议类型.Tls11 |SecurityProtocolType.Tls12;//----------------------------------^
我认为这是一个附带问题,但同样值得解决.
更新
上面引用的 GitHub 问题有一个讨论,最终链接到 .NET Core 2.1 SDK 预览版 2.有以下几点要说:
<块引用>套接字性能和 SocketsHttpHandler
我们对 .NET Core 2.1 中的套接字进行了重大改进.套接字是传出和传入网络通信的基础..NET Core 2.1 中更高级别的网络 API,包括 HttpClient 和 Kestrel,现在基于 .NET 套接字.在早期版本中,这些更高级别的 API 基于本机网络实现.
...
您可以使用以下机制之一来配置进程以使用较旧的 HttpClientHandler:
从代码中,使用 AppContext 类:
AppContext.SetSwitch(System.Net.Http.UseSocketsHttpHandler", false);
AppContext 开关也可以通过配置文件设置.
同样可以通过环境变量 DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER 实现.要选择退出,请将值设置为 false 或 0.
The following code runs without any error in a full .Net framework console program. However, it got the following error when running in .Net core 2.1.
System.AggregateException HResult=0x80131500 Message=One or more errors occurred. Source=System.Private.CoreLib StackTrace: at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) at ConsoleApp1.Program.requestString(String url) in C:source eposConsoleApp1Program.cs:line 38 at ConsoleApp1.Program.Main(String[] args) in C:source eposConsoleApp1Program.cs:line 13 Inner Exception 1: HttpRequestException: The SSL connection could not be established, see inner exception. Inner Exception 2: IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. Inner Exception 3: SocketException: An existing connection was forcibly closed by the remote host
Code:
class Program
{
static void Main(string[] args)
{
var url = "https://google.com";
var (statusCode, html) = requestString(url);
Console.WriteLine("%d %s", statusCode, html);
}
static CookieContainer cc = new CookieContainer();
static HttpClientHandler handler = new HttpClientHandler { AllowAutoRedirect = false, CookieContainer = cc };
public static async Task<(int statusCode, string content)> requestStringAsync(string url)
{
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
// | SecurityProtocolType.Ssl3;
using (var request = new HttpRequestMessage { RequestUri = new Uri(url), Method = HttpMethod.Get })
using (var client = new HttpClient(handler))
{
var response = await client.SendAsync(request); // Error (actual line)
// response.EnsureSuccessStatusCode() |> ignore
var statusCode = (int)response.StatusCode;
var content = await response.Content.ReadAsStringAsync();
return (statusCode, content);
}
}
public static (int statusCode, string content) requestString(string url)
{
return requestStringAsync(url).Result;
}
}
There is a bug for .NET Core 2.1 Preview mentioning this issue. That may be the cause. However, I also notice that your setting of TLS is incorrect. You're currently enabling it, but overwriting all other protocols that have been set. Instead of this:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
You should be using this:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
// ----------------------------------^
I think that's a side issue, but worth fixing all the same.
Update
The referenced GitHub issue above has a discussion which eventually links to the official announcement for .NET Core 2.1 SDK Preview 2. It has the following to say:
Sockets Performance and SocketsHttpHandler
We made major improvements to sockets in .NET Core 2.1. Sockets are the basis of both outgoing and incoming networking communication. The higher-level networking APIs in .NET Core 2.1, including HttpClient and Kestrel, are now based on .NET sockets. In earlier versions, these higher-level APIs were based on native networking implementations.
...
You can use one of the following mechanisms to configure a process to use the older HttpClientHandler:
From code, use the AppContext class:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
The AppContext switch can also be set by config file.
The same can be achieved via the environment variable DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER. To opt out, set the value to either false or 0.
这篇关于.Net 核心 HttpClient 错误?SocketException: 一个现有的连接被远程主机强行关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!