C# HttpClient的cURL请求-如何设置服务器连接(WinInet)的超时
我使用HttpClient通过下面描述的方法发送cURL请求 此方法使用的参数为: SelectedProxy=存储代理参数的自定义类 Parameters.WcTimeout=超时 url,header,content=cURL请求(基于此工具转换为C#) 如果我在没有代理的情况下运行它,它就像一个符咒。 当我使用我首先从Chrome测试的代理发送请求时,我在try{}catch{}上有以下错误。这是错误树C# HttpClient的cURL请求-如何设置服务器连接(WinInet)的超时,c#,curl,timeout,dotnet-httpclient,C#,Curl,Timeout,Dotnet Httpclient,我使用HttpClient通过下面描述的方法发送cURL请求 此方法使用的参数为: SelectedProxy=存储代理参数的自定义类 Parameters.WcTimeout=超时 url,header,content=cURL请求(基于此工具转换为C#) 如果我在没有代理的情况下运行它,它就像一个符咒。 当我使用我首先从Chrome测试的代理发送请求时,我在try{}catch{}上有以下错误。这是错误树 {"An error occurred while sending the reque
{"An error occurred while sending the request."}
InnerException {"Unable to connect to the remote server"}
InnerException {"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond [ProxyAdress]"}
SocketErrorCode: TimedOut
通过使用秒表,我看到时间是在大约30秒后出现的
我根据以下链接或WinHttpHandler尝试了几种不同的处理程序 值得注意的是,WinHttpHandler允许使用不同的错误代码,即错误12002调用WINHTTP\u回调\u状态\u请求\u错误“操作超时”。根本原因是相同的,尽管它有助于找到它的bug(即WinInet),这也证实了@DavidWright所说的关于HttpClient超时管理请求发送的不同部分的说法 因此,我的问题来自与服务器建立连接所需的时间,这会触发WinInet的30秒超时 我的问题是如何更改这些超时?
另一方面,值得注意的是,使用WinInet的Chrome似乎没有出现此超时问题,我的应用程序的很大一部分都基于Cefsharp,通过它,相同的代理可以正确发送请求。我在HttpClient上也遇到过同样的问题。要返回SendAsync,需要做两件事:首先,设置通信发生的TCP通道(SYN、SYN/ACK、ACK握手,如果您熟悉的话),然后通过该TCP通道返回构成HTTP响应的数据。HttpClient的超时仅适用于第二部分。第一部分的超时由操作系统的网络子系统控制,在.NET代码中很难更改该超时 (以下是如何重现这种效果。在两台计算机之间设置一个工作的客户端/服务器连接,这样您就知道名称解析、端口访问、侦听以及客户端和服务器逻辑都可以工作。然后拔下服务器上的网络电缆并重新运行客户端请求。无论发生什么情况,它都会随着操作系统的默认网络超时而超时您在HttpClient上设置的超时。)
我知道的唯一解决方法是在不同的线程上启动自己的延迟计时器,如果计时器首先完成,则取消SendAsync任务。可以使用task.delay和task.WaitAny或使用所需的timeone创建CancellationTokenSource(这基本上只是第一种方式)。在任何一种情况下,您都需要小心取消和读取失去竞争的任务中的异常。我在HttpClient上也遇到了同样的问题。要返回SendAsync,需要做两件事:首先,设置发生通信的TCP通道(SYN、SYN/ACK、ACK握手,如果您熟悉的话)和第二次通过该TCP通道返回构成HTTP响应的数据。HttpClient的超时仅适用于第二部分。第一部分的超时由操作系统的网络子系统控制,在.NET代码中更改该超时非常困难 (以下是如何重现这种效果。在两台计算机之间设置一个工作的客户端/服务器连接,这样您就知道名称解析、端口访问、侦听以及客户端和服务器逻辑都可以工作。然后拔下服务器上的网络电缆并重新运行客户端请求。无论发生什么情况,它都会随着操作系统的默认网络超时而超时您在HttpClient上设置的超时。)
我知道的唯一解决方法是在不同的线程上启动自己的延迟计时器,如果计时器首先完成,则取消SendAsync任务。可以使用task.delay和task.WaitAny或使用所需的timeone创建CancellationTokenSource(这基本上只是第一种方式)。在任何一种情况下,您都需要小心取消并读取失败任务的异常。因此感谢@DavidWright,我了解了一些事情:
HttpRequestMessage
并从HttpClient
开始超时之前,启动到服务器的TCP连接 const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;
var sp = ServicePointManager.FindServicePoint(endpoint);
sp.ConnectionLeaseTimeout = (int)Parameters.ConnectionLeaseTimeout.TotalMilliseconds;
string source = "";
using (var handler = new HttpClientHandler())
{
handler.UseCookies = usecookies;
WebProxy wp = new WebProxy(SelectedProxy.Address);
handler.Proxy = wp;
using (var client = new HttpClient(handler))
{
client.Timeout = Parameters.WcTimeout;
int n = 0;
back:
using (var request = new HttpRequestMessage(new HttpMethod(HttpMethod), endpoint))
{
if (headers != null)
{
foreach (var h in headers)
{
request.Headers.TryAddWithoutValidation(h.Item1, h.Item2);
}
}
if (content != "")
{
request.Content = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded");
}
HttpResponseMessage response = new HttpResponseMessage();
try
{
response = await client.SendAsync(request);
}
catch (Exception e)
{
if(e.InnerException != null)
{
if(e.InnerException.InnerException != null)
{
if (e.InnerException.InnerException.Message.Contains("A connection attempt failed because the connected party did not properly respond after"))
{
if (n <= Parameters.TCPMaxTries)
{
n++;
goto back;
}
}
}
}
// Manage here other exceptions
}
source = await response.Content.ReadAsStringAsync();
}
}
}
return source;
const SslProtocols\u Tls12=(SslProtocols)0x00000C000;
const SecurityProtocolType Tls12=(SecurityProtocolType)\u Tls12;
ServicePointManager.SecurityProtocol=Tls12;
var sp=ServicePointManager.FindServicePoint(端点);
sp.ConnectionLeaseTimeout=(int)Parameters.ConnectionLeaseTimeout.totalMillicons;
字符串源=”;
使用(var handler=new-HttpClientHandler())
{
handler.UseCookies=UseCookies;
WebProxy wp=新的WebProxy(SelectedProxy.Address);
handler.Proxy=wp;
使用(var客户端=新的HttpClient(处理程序))
{
client.Timeout=Parameters.WcTimeout;
int n=0;
背面:
使用(var请求=新的HttpRequestMessage(新的HttpMethod(HttpMethod),端点))
{
const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;
var sp = ServicePointManager.FindServicePoint(endpoint);
sp.ConnectionLeaseTimeout = (int)Parameters.ConnectionLeaseTimeout.TotalMilliseconds;
string source = "";
using (var handler = new HttpClientHandler())
{
handler.UseCookies = usecookies;
WebProxy wp = new WebProxy(SelectedProxy.Address);
handler.Proxy = wp;
using (var client = new HttpClient(handler))
{
client.Timeout = Parameters.WcTimeout;
int n = 0;
back:
using (var request = new HttpRequestMessage(new HttpMethod(HttpMethod), endpoint))
{
if (headers != null)
{
foreach (var h in headers)
{
request.Headers.TryAddWithoutValidation(h.Item1, h.Item2);
}
}
if (content != "")
{
request.Content = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded");
}
HttpResponseMessage response = new HttpResponseMessage();
try
{
response = await client.SendAsync(request);
}
catch (Exception e)
{
if(e.InnerException != null)
{
if(e.InnerException.InnerException != null)
{
if (e.InnerException.InnerException.Message.Contains("A connection attempt failed because the connected party did not properly respond after"))
{
if (n <= Parameters.TCPMaxTries)
{
n++;
goto back;
}
}
}
}
// Manage here other exceptions
}
source = await response.Content.ReadAsStringAsync();
}
}
}
return source;