C# HttpWebRequest在两个服务器500错误后超时

17

我发送了两个C# HttpWebRequests请求,由于"(500) Internal Server Error 500"而抛出异常,第三个尝试却抛出了一个超时异常。为什么它没有再次抛出"(500) Internal Server Error"异常?

当我重新启动应用程序时,它会抛出两个500错误,然后又开始超时。

这是我的代码:

GetPages GetPages = new GetPages();
string test = GetPages.GetPage(); /* Exception: (500) Internal Server Error */
GetPages.Dispose();

GetPages GetPages = new GetPages();
string test = GetPages.GetPage();  /* Exception: (500) Internal Server Error */
GetPages.Dispose();

GetPages GetPages = new GetPages();
string test = GetPages.GetPage();  /* Exception: time out, why? */
GetPages.Dispose();

这是GetPages类和GetPage方法:

namespace MyNamespace
{
    class GetPages
    {
        public string GetPage()
        {
            this.httpRequest = (HttpWebRequest)WebRequest.Create("http://myurl");

            try
            {
                StringBuilder postData = new StringBuilder(100);
                postData.Append("test=test");
                byte[] dataArray = Encoding.UTF8.GetBytes(postData.ToString());

                httpRequest.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
                httpRequest.KeepAlive = false;
                httpRequest.Proxy = null;
                httpRequest.Method = "POST";
                httpRequest.Timeout = 10;
                httpRequest.ContentType = "application/x-www-form-urlencoded";

                httpRequest.ContentLength = dataArray.Length;

                using (this.requestStream = httpRequest.GetRequestStream())
                {
                    requestStream.Write(dataArray, 0, dataArray.Length);
                    requestStream.Flush();
                    requestStream.Close();

                    this.webResponse = (HttpWebResponse)httpRequest.GetResponse();

                    Stream responseStream = webResponse.GetResponseStream();
                    StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8);
                    String responseString = responseReader.ReadToEnd();


                    MessageBox.Show(responseString);
                    return responseString;
                }
            }

            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                return "FAIL";
            }
        }

        public void Dispose()
        {
            System.GC.SuppressFinalize(this);
        }
    }
}

更新

感谢你们的帮助,但我还没有解决这个问题。

现在已经移除了dispose方法。

我把HttpWebRequest httpRequest、HttpWebResponse webResponse和Stream requestStream变成了局部变量,并使用了以下的using语句:

using (webResponse = (HttpWebResponse)httpRequest.GetResponse())
{
    using (Stream responseStream = webResponse.GetResponseStream())
    {
        using (StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8))
        {
            responseString = responseReader.ReadToEnd();
        }
    }
}

另一个更新

现在这是完整的 GetPage 方法:

public string GetPage()
{
    HttpWebRequest httpRequest;
    HttpWebResponse webResponse;
    Stream requestStream;

    try
    {
        StringBuilder postData = new StringBuilder(100);
        postData.Append("test=test");
        byte[] dataArray = Encoding.UTF8.GetBytes(postData.ToString());

        httpRequest = (HttpWebRequest)WebRequest.Create("http://myurl");

        httpRequest.Proxy = null;
        httpRequest.Method = "POST";
        httpRequest.Timeout = 10;
        httpRequest.ContentType = "application/x-www-form-urlencoded";

        httpRequest.ContentLength = dataArray.Length;

        using (requestStream = httpRequest.GetRequestStream())
        {
            /* this is never reached when the time out exception starts 
            so the error seems to be related to too many GetRequestStreams */

            requestStream.Write(dataArray, 0, dataArray.Length);

            webResponse = (HttpWebResponse)httpRequest.GetResponse();

            /* this is never reached when the 500 server error occurs */

            String responseString = "";
            using (Stream responseStream = webResponse.GetResponseStream())
            {
                using (StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8))
                {
                    responseString = responseReader.ReadToEnd();
                    return responseString;
                }
            }
        }
    }

    catch (Exception e)
    {
        return "FAIL";
    }

    return "...";
}

**已解决!!** httpRequest没有被中止。在catch()块中,我添加了httpRequest.abort(),现在它可以正常工作。


那个Dispose方法是我见过的最糟糕的。 - leppie
那么,在进行了这些更改后,您看到了什么行为?完全一样吗? - Jon Skeet
是的,完全一样。 - koen
2个回答

14

猜测这可能是问题所在:

this.webResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseReader = new StreamReader(responseStream, Encoding.UTF8);
String responseString = responseReader.ReadToEnd();

你没有处理任何这些可释放对象。这意味着与Web服务器的连接将保持到最后,因此连接池(每个服务器两个连接)将不允许任何其他请求。

我建议你:

  • GetResponse调用从请求流的using语句中移出。
  • 删除请求流的显式FlushClose调用(仅处理它就足够了)。
  • webResponsewebRequest变量声明为局部变量,除非您确实需要稍后使用它们,在这种情况下应在Dispose方法中处理它们。
  • 对于WebResponseStreamStreamReader,使用using语句。(最后一个不是严格必要的,因为处理掉流就足够了。)
  • 除非您真的需要,否则不要使GetPages实现IDisposable

1
你觉得这是他的Dispose方法吗? :) - leppie
1
@koen: 嗯...这让我感到惊讶。有可能是因为出现了异常,没有执行到释放响应的操作。你可以尝试在WebException中捕获异常并进行响应的释放...但如果你真的需要这么做,那就相当糟糕了 :( - Jon Skeet
1
@jon:你能看一下整个方法吗?(我已经在第一篇帖子中添加了另一个更新) - koen
2
@jon:我不得不在catch块中使用Abort()方法手动中止httpRequest。非常感谢你的时间。 - koen
1
@koen:哎呀,那太奇怪了 :( - Jon Skeet
显示剩余3条评论

8

HTTP协议规定同一服务器只能同时建立两个连接。在成功或失败读取后关闭responseStream


我现在已经用using语句包装了responseStream(请参见第一篇帖子中的更新)。这样就足够了吗? - koen
1
是的,我认为那就是连接松动而没有关闭的地方。 - Aliostad
奇怪,我把responseStream放在using块中,但仍然超时。 - Jaanus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接