Can't set HttpWebRequest timeout higher than 1

2019-04-04 19:04发布

问题:

I am running into an issue where HttpWebRequest won't respect a timeout value higher than 100 seconds when doing a POST. However, if the request is a GET, a timeout value higher than 100 seconds is respected. The timeout exception is thrown at the .GetResponse() call. I'm setting all the timeout values I have been able to discover but it seems I am missing one, or there is a bug in the framework.

This is a C# app targeting the .NET Framework 3.5, built using Visual Studio 2008. The web server is IIS 6.0 with a connection timeout set to the default 120 seconds, keep-alives enabled... again GET requests respect the timeout value I specify, POST requests respect the timeout if <= 100 seconds.

Here is my code:

int timeout = 200000; // 200 seconds
HttpWebRequest proxyRequest = (HttpWebRequest)WebRequest.Create(serverUrl);
proxyRequest.Accept = clientRequest.AcceptTypes.ToDelimitedString(", ");
proxyRequest.Method = "POST"
proxyRequest.UserAgent = clientRequest.UserAgent;
proxyRequest.Timeout =  timeout;
proxyRequest.ReadWriteTimeout = timeout;
proxyRequest.KeepAlive = false;
proxyRequest.AllowAutoRedirect = false;
proxyRequest.ServicePoint.Expect100Continue = false;
proxyRequest.ServicePoint.MaxIdleTime = timeout;
proxyRequest.ServicePoint.ConnectionLeaseTimeout = -1;

try
{
    // add post data
    request.ContentType = "application/x-www-form-urlencoded";
    byte[] postData = Encoding.UTF8.GetBytes("somedata=7&moredata=asdf");
    // set some post data
    request.ContentLength = postData.Length;
    using (Stream stream = request.GetRequestStream())
    {
        stream.Write(postData, 0, postData.Length);
        stream.Close();
    }

    // UPDATE
    // don't set Timeout here! It will be ignored
    // proxyRequest.Timeout = timeout;

    // Timeout exception thrown here if GetResponse doesn't return within 100 seconds
    // even though the Timeout value is set to 200 seconds.
    using (HttpWebResponse proxyResponse = (HttpWebResponse)proxyRequest.GetResponse())
    {
        using (Stream stream = proxyResponse.GetResponseStream())
        {
            using (StreamReader reader = new StreamReader(stream, Encoding.Default))
            {
                string content = reader.ReadToEnd();
                [other pointless code for this example]
                reader.Close();
            }
            stream.Close();
        }
        proxyResponse.Close();
    }
}
finally
{
    proxyRequest.Abort();
}

When I have set the timeout value to 5 seconds, I will receive a timeout exception after 5 seconds just as one would expect. This proves the Timeout value isn't being completely ignored.

Has anybody else run into this issue? Will using the Async version of GetResponse get around this issue? Any and all thoughts welcome, I've been stuck on this for a couple days.

UPDATE

I can get the POST to respect the timeout value if I don't post any data (which isn't very useful). However, as soon as I post any data at all and ContentLength is > 0, it timesout at 100 seconds. Also, no proxies are involved.

UPDATE 2

Added the POST data to the example and a comment on where NOT to set the Timeout property

回答1:

I figured it out. This is an example of DRY coding coming back and biting me in the butt. The code above is a paraphrase of my real code, and as such the code above will work fine.

The issue was I was setting the Timeout value after I had already called proxyRequest.GetRequestStream() to add the POST data. Because I was setting both the Timeout and ReadWriteTimeout properties, the shortest timeout was winning. In the case of a POST request, even though the framework let me set the Timeout value AFTER a call to GetRequestStream, it ignored whatever value was set (and instead used the default 100 seconds even though inspecting the Timeout property after setting it showed it was set to what I expected). I wish setting the Timeout property worked the same as setting the ReadWriteTimeout property: If you attempt to set the ReadWriteTimeout property after you have called GetRequestStream, it throws an exception. If Timeout did the same thing, that would have saved me a TON of time. I should have caught this sooner, but I'll chalk it up to a learning experience.

So the moral of the story: Set all the timeout properties for your HttpWebRequest right when you create it.



回答2:

Do you have a web proxy between your client and the server? Perhaps that's using a timeout itself.

I suggest you use Wireshark to see what's happening at the network level - and in particular whether anything happens on the network at 100 seconds.