使用代理处理HttpWebResponse的很长/无限超时

时间:2019-02-20 01:39:59

标签: c# httpwebresponse

我与代理服务器建立了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的另一个答案中看到了这一点,但这没有帮助。

MSDN上的

HttpWebRequest.Timeout说:

  

获取或设置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;
        }
    }
}

0 个答案:

没有答案