System.Net.Http.HttpClient 类

本文提供了此 API 参考文档的补充说明。

HttpClient 实例充当发送 HTTP 请求的会话。 HttpClient实例是应用于该实例执行的所有请求的设置集合。 此外,每个 HttpClient 实例都使用自己的连接池,将请求与其他实例执行 HttpClient 的请求隔离开来。

实例化

HttpClient 旨在实例化一次,并在应用程序的整个生命周期内重复使用。 在 .NET Core 和 .NET 5+ 中,HttpClient 池处理程序实例中的连接,并在多个请求之间重复使用连接。 如果实例化每个请求的 HttpClient 类,则大量负载下可用的套接字数将耗尽。 这种耗尽将导致 SocketException 错误。

可以通过将“处理程序”(或 HttpClientHandlerSocketsHttpHandler .NET Core 2.1 或更高版本)作为构造函数的一部分来配置其他选项。 提交请求后,无法更改处理程序上的连接属性,因此,如果需要更改连接属性,则创建一个新的 HttpClient 实例的原因之一。 如果不同的请求需要不同的设置,这还可能导致应用程序具有多个 HttpClient 实例,其中每个实例已正确配置,然后在相关客户端上发出请求。

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

public class GoodController : ApiController
{
    private static readonly HttpClient httpClient;

    static GoodController()
    {
        var socketsHandler = new SocketsHttpHandler
        {
            PooledConnectionLifetime = TimeSpan.FromMinutes(2)
        };

        httpClient = new HttpClient(socketsHandler);
    }
}

作为仅创建一个 HttpClient 实例的替代方法,还可以用于 IHttpClientFactory 管理 HttpClient 实例。 有关详细信息,请参阅 HttpClient 使用准则

衍生

它还 HttpClient 充当更具体的 HTTP 客户端的基类。 例如,FacebookHttpClient 提供特定于 Facebook Web 服务的其他方法(例如,方法 GetFriends )。 派生类不应替代类上的虚拟方法。 请改用接受 HttpMessageHandler 的构造函数重载来配置任何预请求或请求后处理。

传输

HttpClient这是一个高级 API,用于包装其运行的每个平台上可用的较低级别功能。

在每个平台上, HttpClient 尝试使用最佳可用传输:

主机/运行时 后端
Windows/.NET Framework HttpWebRequest
Windows/Mono HttpWebRequest
Windows/UWP Windows 本机 WinHttpHandler 版本(支持 HTTP 2.0)
Windows/.NET Core 1.0-2.0 Windows 本机 WinHttpHandler 版本(支持 HTTP 2.0)
Android/Xamarin 在生成时选择。 HttpWebRequest可以使用或配置为使用 Android 的本机HttpURLConnection
iOS, tvOS, watchOS/Xamarin 在生成时选择。 HttpWebRequest可以使用或配置为使用 Apple(NSUrlSession支持 HTTP 2.0)
macOS/Xamarin 在生成时选择。 HttpWebRequest可以使用或配置为使用 Apple(NSUrlSession支持 HTTP 2.0)
macOS/Mono HttpWebRequest
macOS/.NET Core 1.0-2.0 libcurl基于 HTTP 传输(支持 HTTP 2.0)
Linux/Mono HttpWebRequest
Linux/.NET Core 1.0-2.0 libcurl基于 HTTP 传输(支持 HTTP 2.0)
.NET Core 2.1 及更高版本 System.Net.Http.SocketsHttpHandler

用户还可以通过调用HttpClient采用 a HttpMessageHandler的构造函数来配置特定的传输HttpClient

.NET Framework 和 Mono

默认情况下,在 .NET Framework 和 Mono 上, HttpWebRequest 用于将请求发送到服务器。 可以通过使用参数在构造函数重载 HttpMessageHandler 之一中指定不同的处理程序来修改此行为。 如果需要身份验证或缓存等功能,则可以用于 WebRequestHandler 配置设置,实例可以传递给构造函数。 返回的处理程序可以传递给具有 HttpMessageHandler 参数的构造函数重载。

.NET Core

从 .NET Core 2.1 开始, System.Net.Http.SocketsHttpHandler 该类而不是 HttpClientHandler 提供更高级别的 HTTP 网络类(例如 HttpClient)使用的实现。 使用 SocketsHttpHandler 提供了许多优势:

  • 对照以前的实现,可以看到显著的性能改进。
  • 消除平台依赖项,从而简化了部署和服务。 例如, libcurl 不再依赖于适用于 macOS 的 .NET Core 和适用于 Linux 的 .NET Core。
  • 在所有 .NET 平台中一致的行为。

如果此更改不可取,在 Windows 上,可以通过引用其 NuGet 包并将其手动传递给 HttpClient 的构造函数WinHttpHandler继续使用。

使用运行时配置选项配置行为

某些方面 HttpClient的行为可通过 运行时配置选项进行自定义。 但是,这些开关的行为因 .NET 版本而异。 例如,在 .NET Core 2.1 - 3.1 中,可以配置是否 SocketsHttpHandler 默认使用,但从 .NET 5 开始,该选项不再可用。

连接池

如果可能,HttpClient 会池 HTTP 连接,并将它们用于多个请求。 这可以具有显著的性能优势,尤其是对于 HTTPS 请求,因为连接握手仅执行一次。

连接池属性可以在构造期间配置HttpClientHandler或传入,包括MaxConnectionsPerServerPooledConnectionIdleTimeoutPooledConnectionLifetimeSocketsHttpHandler

释放 HttpClient 实例会关闭打开的连接并取消任何挂起的请求。

注意

如果将 HTTP/1.1 请求并发发送到同一服务器,则可以创建新连接。 即使重复使用 HttpClient 实例,如果请求速率较高,或者存在任何防火墙限制,由于默认 TCP 清理计时器,可能会耗尽可用套接字。 若要限制并发连接数,可以设置属性 MaxConnectionsPerServer 。 默认情况下,并发 HTTP/1.1 连接数不受限制。

缓冲和请求生存期

默认情况下,HttpClient 方法(除外 GetStreamAsync)缓冲来自服务器的响应,在返回异步结果之前将所有响应正文读取到内存中。 这些请求将继续,直到发生以下情况之一:

可以使用某些方法重载上可用的参数,根据 HttpCompletionOption 每个请求更改缓冲行为。 此参数可用于指定在仅读取响应标头后或读取和缓冲响应内容后是否 Task<TResult> 应考虑完成该参数。

如果命名空间中使用HttpClientSystem.Net.Http和相关类的应用打算下载大量数据(50 兆字节或更多),则应用应流式传输这些下载内容,而不使用默认缓冲。 如果使用默认缓冲,则客户端内存使用量将非常大,这可能会导致性能大幅降低。

线程安全性

以下方法是线程安全的:

代理

默认情况下,HttpClient 根据平台从环境变量或用户/系统设置读取代理配置。 可以通过按 WebProxy 优先级顺序传递或 IWebProxy 传递给此行为:

  • Proxy在 HttpClient 构造过程中传入的 HttpClientHandler 的属性
  • DefaultProxy静态属性(影响所有实例)

可以使用 UseProxy. Windows 用户的默认配置是尝试并使用网络发现来检测代理,这可能很慢。 对于已知不需要代理的高吞吐量应用程序,应禁用代理。

只有在使用 HttpClient 发出第一个请求之前,才应更改代理设置(例如 Credentials)。 首次使用 HttpClient 后所做的更改可能不会反映在后续请求中。

超时

可用于 Timeout 为来自 HttpClient 实例的所有 HTTP 请求设置默认超时。 超时仅适用于导致启动请求/响应的 xxxAsync 方法。 如果达到超时,则会 Task<TResult> 取消该请求。

如果在构造 HttpClient 对象时传入 SocketsHttpHandler 实例,则可以设置一些额外的超时:

properties 说明
ConnectTimeout 指定在请求需要创建新的 TCP 连接时使用的超时。 如果发生超时,请求 Task<TResult> 将被取消。
PooledConnectionLifetime 指定用于连接池中每个连接的超时。 如果连接处于空闲状态,则连接会立即关闭;否则,连接在当前请求结束时关闭。
PooledConnectionIdleTimeout 如果连接池中的连接长时间处于空闲状态,则连接将关闭。
Expect100ContinueTimeout 如果请求具有“Expect: 100-continue”标头,则会延迟发送内容,直到超时或收到“100-continue”响应为止。

HttpClient 仅在创建连接时解析 DNS 条目。 它不跟踪 DNS 服务器指定的任何生存时间 (TTL)。 如果 DNS 条目定期更改(在某些情况下可能发生),则可以使用 PooledConnectionLifetime 限制连接的生存期,以便在替换连接时需要 DNS 查找。