HttpClient 的使用准则

System.Net.Http.HttpClient 类用于发送 HTTP 请求以及从 URI 所标识的资源接收 HTTP 响应。 HttpClient 实例是应用于该实例执行的所有请求的设置集合,每个实例使用自身的连接池,该池将其请求与其他请求隔离开来。 从 .NET Core 2.1 开始,SocketsHttpHandler 类提供实现,使行为在所有平台上保持一致。

如果你使用的是 .NET 5+(包括 .NET Core),则在使用 HttpClient 时需要记住一些注意事项。

DNS 行为

HttpClient 仅在创建连接时解析 DNS 条目。 它不跟踪 DNS 服务器指定的任何生存时间 (TTL)。 如果 DNS 条目定期更改(这可能在某些容器方案中发生),客户端将不遵循这些更新。 若要解决此问题,可以通过设置 PooledConnectionLifetime 属性来限制连接的生存期,以便在替换连接时要求执行 DNS 查找。 请考虑以下示例:

var handler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(15) // Recreate every 15 minutes
};
var client = new HttpClient(handler);

上述 HttpClient 配置为重复使用连接 15 分钟。 PooledConnectionLifetime 指定的时间范围过后,系统会关闭连接,然后创建一个新连接。

共用连接

HttpClient 的连接池链接到其基础 HttpMessageHandler。 释放 HttpClient 实例时,会释放所有先前使用的连接。 如果稍后向同一服务器发送请求,则会创建一个新连接。 此外还会造成性能损失,因为这需要一个新的 TCP 端口。 如果请求速率很高,或者存在任何防火墙限制,则可能会耗尽可用的套接字,因为存在默认的 TCP 清理计时器。

  • 在 .NET Core 和 .NET 5+ 中:

    • 根据预期的 DNS 更改,使用 static 或单一 HttpClient 实例并将 PooledConnectionLifetime 设置为所需间隔(例如两分钟)。 这可以解决套接字耗尽和 DNS 更改的问题,且不会增加 IHttpClientFactory 的开销。 如果需要模拟处理程序,可以单独注册它。

    • 使用 IHttpClientFactory,可以针对不同的用例使用多个以不同方式配置的客户端。 但请注意,工厂创建的客户端生存期较短,一旦创建客户端,工厂就不再可以控制它。

      工厂合并 HttpMessageHandler 实例,如果其生存期尚未过期,则当工厂创建新的 HttpClient 实例时,可以从池中重用处理程序。 这种重用避免了任何套接字耗尽问题。

      如果需要 IHttpClientFactory 提供的可配置性,我们建议使用类型化客户端方法

  • 在 .NET Framework 中,使用 IHttpClientFactory 管理 HttpClient 实例。 如果为每个请求创建新的客户端实例,则可能会耗尽可用的套接字。

    提示

    如果应用需要 Cookie,请考虑禁用自动 Cookie 处理或避免使用 IHttpClientFactory。 共用 HttpMessageHandler 实例会导致共享 CookieContainer 对象。 意外的 CookieContainer 对象共享通常会导致错误的代码。

另请参阅