当前位置: 首页 > 知识库问答 >
问题:

HttpClient和HttpClientHandler是否必须在请求之间进行处理?[闭门]

寿伟
2023-03-14

系统。网。http://http.HttpClient和System.网。http://http.HttpClientHandler在。NET框架4.5实现IDisposable(通过System.网。http://http.HttpMessageInvoker)。

使用语句的文档说明:

通常,当您使用IDisposable对象时,应该在using语句中声明并实例化它。

此答案使用以下模式:

var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("foo", "bar"),
        new KeyValuePair<string, string>("baz", "bazinga"),
    });
    cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
    var result = client.PostAsync("/test", content).Result;
    result.EnsureSuccessStatusCode();
}

但是微软最明显的例子不是显式或隐式地调用Dispose()。例如:

  • 宣布HttpClient发布的原始博客文章。
  • HttpClient的实际MSDN留档。
  • 翻译样本
  • Google MapsSample
  • 世界银行样本

在公告的评论中,有人问微软员工:

在检查示例之后,我发现您没有对HttpClient实例执行dispose操作。我已经在我的应用程序上使用了所有HttpClient实例和using语句,我认为这是正确的方法,因为HttpClient实现了IDisposable接口。我走对了吗?

他的回答是:

一般来说,这是正确的,尽管您必须小心使用和异步,因为它们并没有真正混合在一起。净4,在。NET4.5可以在“using”语句中使用“await”。

顺便说一句,你可以重复使用相同的HttpClient,因为很多次都是[,因为]你喜欢,所以通常你不会创建/处置他们所有的时间。

第二段对这个问题来说是多余的,这个问题不关心你可以使用HttpClient实例多少次,而是关心在你不再需要它之后是否有必要处理它。

(更新:事实上,第二段是答案的关键,如下@DPeden所述。)

所以我的问题是:

>

  • 鉴于当前的实现(.NET Framework 4.5),是否有必要在HttpClient和HttpClientHandler实例上调用Dispose()?澄清:我所说的“必要”是指不进行处理会产生任何负面后果,例如资源泄漏或数据损坏风险。

    如果没有必要,这会是一个“好的实践”吗,因为他们实现了IDisposable?

    如果有必要(或建议),上述代码是否安全地实现了它(对于.NETFramework 4.5)?

    如果这些类不需要调用Dispose(),为什么它们被实现为IDisposable?

    如果他们需要,或者如果这是一种推荐做法,Microsoft示例是否具有误导性或不安全性?


  • 共有3个答案

    刘京
    2023-03-14

    根据我的理解,只有在锁定您以后需要的资源(如特定连接)时,才需要调用Dispose()。总是建议你释放不再使用的资源,即使你不再需要它们,仅仅因为你通常不应该持有你不使用的资源(双关语)。

    微软的例子不一定是不正确的。使用的所有资源将在应用程序退出时释放。在这个例子中,这几乎是在使用完HttpClient之后立即发生的。在类似的情况下,显式调用Disals()有些多余。

    但是,一般来说,当一个类实现了IDisposable时,我们的理解是,您应该在完全准备好并能够处理它的实例后尽快对其进行Dispose()。我认为这在HttpClient这样的情况下尤其如此,在这种情况下,没有明确记录资源或连接是否被保留/打开。如果连接[很快]将再次被重用,您将希望放弃对它的Dipose()ing——在这种情况下,您还没有“完全准备好”。

    另请参见:IDisposable。Dispose方法以及何时调用Dispose

    上官和惬
    2023-03-14

    目前的答案有点混乱和误导,并且缺少一些重要的DNS含义。我将试图总结清楚的情况。

    1. 一般来说,大多数IDisposable对象在处理完后应该被理想地处理掉,尤其是那些拥有命名/共享操作系统资源的对象。HttpClient也不例外,因为正如达雷尔·米勒指出的那样,它分配取消令牌和请求/响应身体可以是不受管理的流。
    2. 然而,HttpClient的最佳实践表明,您应该创建一个实例并尽可能多地重用它(在多线程场景中使用其线程安全成员)。因此,在大多数情况下,你永远不会仅仅因为你一直需要它就扔掉它。
    3. 重复使用相同的HttpClient"永远"的问题是,底层HTTP连接可能对最初解析的DNS IP保持打开状态,而不管DNS更改如何。在蓝色/绿色部署和基于DNS的故障转移等场景中,这可能是一个问题。有各种各样的方法来处理这个问题,最可靠的方法是在DNS更改发生后,服务器发送一个连接:关闭标头。另一种可能性涉及在客户端循环使用HttpClient,可以是周期性的,也可以是通过某种了解DNS更改的机制。更多信息请参见https://github.com/dotnet/corefx/issues/11224(我建议在盲目使用链接博客文章中建议的代码之前仔细阅读它)。
    黄正浩
    2023-03-14

    一般的共识是,你不(不应该)需要处置HttpClient。

    许多密切参与其工作方式的人都说过这一点。

    请参阅Darrel Miller的博客文章和相关的SO帖子: HttpClient抓取导致内存泄漏,以供参考。

    我还强烈建议您阅读HttpClient一章,了解如何使用ASP设计可演进的Web API。NET获取引擎盖下正在发生的事情的上下文,特别是此处引用的“生命周期”部分:

    尽管HttpClient确实间接地实现了IDisposable接口,但HttpClient的标准用法不是在每次请求后都处理它。只要应用程序需要发出HTTP请求,HttpClient对象就会一直存在。在多个请求之间存在一个对象可以设置DefaultRequestHeader,并防止您在每个请求上重新指定诸如CredentialCache和CookieContainer之类的内容,这是HttpWebRequest所必需的。

    甚至打开DotPeek。

     类似资料:
    • 我对我的servlet执行请求 和联机: 一个可能相关的问题:我很清楚logcat中的“无法et连接工厂客户端”任何可能导致该问题的东西都不是我的情况 API密钥正确,正确debug.keystore的路径 清单中的所有权限 在清单中也使用-library android:name=“com.google.android.maps 地图显示正确,在缩放/移动时刷新。

    • 问题内容: 我有一个需要在网络上重复请求内容的应用程序。现在,服务器端实现遵循使用标头进行http缓存的标准。我想知道是否有扩展版本的HttpClient或其他工具来存储响应并与标头进行交互以进行自动缓存。如果没有一个很好的选择,那么我想跳过已有的工具。 谢谢 问题答案: Apache HttpClient 从4.1开始就引入了CachingHttpClient,但是Android默认仅包含4.0

    • 问题内容: 我不想拥有hibernate.cfg.xml文件。而是我想通过我的代码进行所有配置,如下所示。 我已经尝试了上述方法。但是我面临的问题是hibernate抛出一个异常,说“ ”。 保留文件真的是强制性的吗? 提前致谢 问题答案: 我相信这是由于您对对象的调用。尝试删除该文件,hibernate状态将不会查找不存在的文件。基本上,您是通过对象设置所有必需的属性,因此并不需要告诉Hiber

    • 问题内容: 我试图通过在jsp中编写一些代理代码来从我的计算机本地向其他域进行ajax调用。这是我的jQuery AJAX代码,正在调用proxy.jsp页面。 我的JSP文件是:- 当我检查响应时,我正在解析的XML文件收到此错误: XMl文件是这样的: 我在这里做什么错..任何建议将不胜感激.. 问题答案: 错误消息实际上是正确的,如果不是很明显的话。它说您的DOCTYPE必须具有SYSTEM

    • 问题内容: 由于类,结构和枚举都具有构造函数,属性和计算属性,因此在它们之间进行选择时应如何推理? 问题答案: ChristopheD和Jack Jack的回答很好,但是我觉得他们没有触及枚举,或者错过了它们的重要性。Swift枚举(即将)是代数数据类型的完整实现。传统上,类和结构用于以面向对象的语言对数据进行建模,但是枚举通常仅限于用作将变量的值限制为有限可能性的便捷方法。例如(C ++): S

    • 我有两个docker容器作为docker-compose文件的一部分运行,ContainerA是localstack,我在其中运行一个lambda函数,它试图使用以下简化代码向ContainerB发出HTTP POST请求: 这会引发以下异常: 当这个请求从控制台成功时,我非常确信这不是我的docker容器之间的网络问题。