41

我正在使用HttpWebRequest, 并且正在处理响应流。是否有正确的处理方法HttpWebRequest,因为它不包含 close 或 dispose 方法?

4

5 回答 5

49

我有一个类似的问题,这里的答案没有给我我需要的信息。因此,即使有一个公认的答案,我也会添加我学到的知识来帮助下一个人。

1)正如其他一些答案所提到的,您可以使用using从 HttpWebRequest/WebRequest 返回的流。这只是很好的标准 c# 编程。

但它并没有真正解决 OP 的问题(或我的问题),即关于处理 HttpWebRequest 对象本身的问题。

2) 尽管获取 HttpWebRequest 的函数名为“Create”,但没有匹配的 Destroy、Close、Dispose 或任何其他可用于从创建的对象中释放资源的机制。

这基本上是目前公认的答案。

3)但是这里的所有答案都暗示(除了流)没有任何重要的东西需要关闭。这并不完全正确。

使用ProcMon,您可以看到TCP Connect,TCP SendTCP Receive调用时发生的情况GetResponse()。这是我希望看到的。但是什么时候TCP Disconnect发生呢?我的假设是,这会在您完成接收响应之后发生,或者最坏的情况是在对象被 GC 处理时发生。但现实更有趣。

相反,TCP 连接在调用后恰好保持活动 2 分钟。我的第一个想法是 GC 需要多长时间才能解决它,但不。您可以在 GC.Collect() 循环中坐在那里 2 分钟,直到 2 分钟结束才放手。这会在客户端和服务器上保持连接打开,并在这 2 分钟内导致(一些)额外的网络流量以保持连接处于活动状态。

另一个有趣的事情是,即使您调用“创建”,这并不意味着必须创建另一个 TCP 连接。例如,考虑一下:

static void Doit(string domain)
{
    HttpWebRequest hr = (HttpWebRequest)WebRequest.Create(domain);

    using (HttpWebResponse response = (HttpWebResponse)hr.GetResponse())
        using (Stream receiveStream = response.GetResponseStream())
            using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
                Console.WriteLine(readStream.ReadToEnd());
}

现在,如果我用以下方式调用它:

Doit("http://www.foo.bar");

它将创建 1 个 TCP 连接。它将保持活动状态 2 分钟(或直到程序退出)。但是,如果我这样做:

Doit("http://www.foo.bar");
Thread.Sleep(20000);
Doit("http://www.foo.bar");

现在它将为第一次调用创建一个连接,然后为第二次调用重用该连接。这意味着 TCP 连接将保持活动状态总共 2:20 分钟。因此,即使我们调用“创建”,它也不是从头开始创建连接。

大多数情况下,这是一件好事。建立连接(尤其是 HTTPS 连接)可能是一个昂贵的过程。自动为您避免这种情况的系统(可能)是一件好事。这样,您可以有效地检索网页的 html,然后检索任何相关的支持文件(css、img 文件等),而无需每次都经过连接过程。

但是,如果您要连接的服务器只支持有限数量的连接怎么办?像这样无缘无故地将连接捆绑起来可能是一个真正的问题。或者可能出于安全原因,您不能长时间保持连接打开?或者,也许您只是肛门,并且想在完成后立即关闭它。

对于这些情况,您可以尝试使用HttpWebRequest.KeepAlive. 将此设置为false(默认值为true)会导致上面的每个示例都使用自己的连接,一旦完成就关闭它们。因此,整个连接/发送/接收/断开过程可以在不到一秒的时间内完成。

供参考:

  • 虽然您可以使用 WebRequest.InitializeLifetimeService 来获取 ILease,但更改租约上的值不会影响此处的超时。
  • 您可以使用支持 Dispose 的 WebClient,而不是使用 WebRequest。然而,即使在调用 Dispose 之后,底层 TCP 连接仍会挂起 2 分钟。

总之:说您不需要担心关闭 HttpWebClient 可能通常是正确的,但您可能需要注意其中的一些含义。这种行为有充分的理由,但如果您不知道这种情况正在发生,您无法确定这是否对您的特定应用程序有利。

FWIW

于 2017-02-15T05:40:32.643 回答
43

如果该类有特殊的处理要求,它会实现 IDisposable。由于它没有实现 IDisposable,您可能会认为您不需要做任何特别的事情。

于 2009-04-04T03:31:43.180 回答
3

httpwebRequest 没有实现 IDisposable,因为它可以创建一个 Stream,它实现了 IDisposable。因此,您不必担心将其丢弃。

如果您担心,您可能想要使用 IDisposable 的 WebClient:

using (WebClient c = new WebClient())
{
using (Stream stream = c.OpenRead(url))
{
//
}
}
于 2009-04-04T03:36:27.597 回答
2

您可以使用:

    var webRequest = WebRequest.Create(ActionUrl)
    using (var webResponse = webRequest.GetResponse())
    {}

为您的实施。当我使用 WebRequest 类在很短的时间内触发多个请求时,将 GetResponse() 包装在 using 块中可以防止应用程序挂起。

于 2016-05-04T22:02:51.200 回答
-3

HttpWebRequest 没有实现 IDisposable 所以它不需要处理。完成后,只需将 httprequest 对象设置为 null 即可。

希望能帮助到你

于 2009-04-04T03:31:36.597 回答