我与代理服务器建立了HTTPS HttpWebRequest
连接。问题是,如果代理由于某种原因拒绝连接(例如,键入错误的地址),则线程在HttpWebResponse
处停留的时间很长/可能是无限的。
我要实现的目标是等待2秒钟让代理执行请求,如果这2秒钟没有成功,请抛出异常并改用其他代理。
我找不到任何类似的问题可以帮助我。
我的请求如下:
HttpWebRequest request2 = (HttpWebRequest)WebRequest.Create("https://.../");
request2.Method = "GET";
request2.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
if (proxyAddress != null)
{
request2.Proxy = new WebProxy(proxyAddress);
}
else
{
request2.Proxy = null;
}
request2.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763";
request2.Headers.Add("Accept-Language", "en-US");
request2.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request2.Timeout = 2000;
request2.ReadWriteTimeout = 2000;
request2.ContinueTimeout = 2000;
string result = string.Empty;
try
{
// Timeout - https://stackoverflow.com/questions/4040538/timeout-with-httpwebresponse-in-net
using (HttpWebResponse response2 = (HttpWebResponse)request2.GetResponse())
{
using (StreamReader reader = new StreamReader(response2.GetResponseStream()))
{
result = reader.ReadToEnd();
}
}
}
catch (WebException e)
{
if (e.InnerException is SocketException)
{
// Proxy error
}
// Proxy error
}
我也忽略带有以下代码的证书检查:
ServicePointManager.DefaultConnectionLimit = 500;
ServicePointManager.Expect100Continue = false;
ServicePointManager.DnsRefreshTimeout = -1;
ServicePointManager.EnableDnsRoundRobin = false;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)4080;
ServicePointManager.ServerCertificateValidationCallback += (sender2, certificate, chain, sslPolicyErrors) => true;
我尝试将DefaultConnectionLimit
设置为4,因为我在SO的另一个答案中看到了这一点,但这没有帮助。
获取或设置GetResponse()的超时值(以毫秒为单位) 和GetRequestStream()方法。
但基本上对代理请求没有任何影响。
我看到了this answer,并且我正在使用.NET Framework 4.5,但是它肯定与我的机器无关,因为有一个类似的应用程序,该功能运行良好,并且我也在VM上进行了测试
我不知道那是怎么回事。
编辑: 我在this thread上找到了。它说这是一个错误,但是那是9年前的,所以应该修复它。没有其他人得到此错误吗?
编辑: 感谢@shingo,我能够使其正常运行,但是我可以以某种方式进行适当的错误处理吗?
private void ReadCallback(IAsyncResult asyncResult)
{
HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
try
{
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
RequestResult = reader.ReadToEnd();
}
}
}
catch (WebException e)
{
Console.WriteLine(e.Message);
}
_manualResetEvent.Set();
}
private void TimeoutCallback(object state, bool timedOut)
{
if (timedOut)
{
HttpWebRequest request = (HttpWebRequest)state;
if (request != null)
{
request.Abort();
}
}
}
// Usage
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
IAsyncResult response = request.BeginGetResponse(new AsyncCallback(ReadCallback), request);
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
ThreadPool.RegisterWaitForSingleObject(response.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, 2000, true);
// The response came in the allowed time. The work processing will happen in the callback function
_manualResetEvent.WaitOne();
无论什么EndGetResponse
弹出异常The remote server returned an error: (403) Forbidden.
,始终存在任何错误。
用于正确处理错误的旧代码:
try
{
// Writing content because ContentLength > 0
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponseWithoutException())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
RequestResult = reader.ReadToEnd();
}
}
}
catch (WebException e)
{
if (e.InnerException is SocketException)
{
return ResultType.ProxyError;
}
return ResultType.ProxyError;
}
public static class WebRequestExtensions
{
public static WebResponse GetResponseWithoutException(this WebRequest request)
{
if (request == null)
throw new ArgumentNullException("request");
try
{
return request.GetResponse();
}
catch (WebException e)
{
if (e.Response == null)
throw;
return e.Response;
}
}
}