如何避免 .NET 中 HttpClient 的 DNS 失效问题?
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何避免 .NET 中 HttpClient 的 DNS 失效问题?相关的知识,希望对你有一定的参考价值。
HttpClient 可以用来发送 HTTP 请求。HttpClient 可以设置为单例并在整个生命周期中重复使用。这是因为,HttpClient 有一个“连接池”来重用连接并减少 TCP 连接的数量。因此,如果您向同一主机发送多个请求,它们将重用相同的连接。这样,应用程序就不会在重负载下耗尽可用的套接字数量(如果使用 HttpClient 的方式有误,将会影响软件的稳定性)。此外,这种方式可以避免对同一主机的每个请求进行握手(TCP 握手、TLS 握手)从而提高应用程序的性能。
保持连接打开对提升性能有益处,但必须避免保持陈旧的连接。如果主机更改了 IP 地址怎么办?例如,如果 DNS TTL 过期,主机可能会更改其 IP 地址。在这种情况下,应该关闭已经打开的连接并打开一个新的。HttpClient 不会自动执行此操作,因为它感知不到 DNS TTL。尽管如此,可以通过设置超时时间来自动关闭链接。这样,下一个请求将需要重新打开连接,并使用 DNS 查找新的 IP 地址。
您可以使用 SocketsHttpHandler 来配置 HttpClient 及其连接池的行为。有 2 个属性需要配置:PooledConnectionIdleTimeout和PooledConnectionLifetime 。这些属性允许在一定时间后强制关闭连接。这样,下一个请求将打开一个新连接,以反映 DNS 或其他网络更改。
默认情况下,空闲连接会在 1 分钟后关闭。但是,活动连接永远不会关闭。因此必须明确设置PooledConnectionLifetime 为所需的值。
using System.Net;
using var socketHandler = new SocketsHttpHandler()
// 池中连接的最大空闲时间。当达到最大空闲时间时,连接将会被释放。
// 在 .NET 6 中,该属性的默认值是 1 分钟
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1),
//此属性定义池中连接的最大连接寿命,无论连接是空闲还是活动性。
//在 .NET 6 中,该属性的默认值是从不过期
//设置超时时间以反映 DNS 或其他网络更改
PooledConnectionLifetime = TimeSpan.FromMinutes(1),
;
using var httpClient = new HttpClient(socketHandler);
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
while (await timer.WaitForNextTickAsync())
_ = await httpClient.GetStringAsync("https://www.coderbusy.com");
避免 DNS 问题的另一种方法是使用
IHttpClientFactory
。
如何调试
如果您想知道 HttpClient 何时查询 DNS,可以使用 EventListener 。这是因为 System.Net.* 命名空间下的对象会发出 ETW 追踪信息。
using System.Diagnostics.Tracing;
_ = new NetEventListener();
using var socketHandler = new SocketsHttpHandler()
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1),
PooledConnectionLifetime = TimeSpan.FromSeconds(10),
;
using var httpClient = new HttpClient(socketHandler);
var timer = new PeriodicTimer(TimeSpan.FromSeconds(2));
while (await timer.WaitForNextTickAsync())
_ = await httpClient.GetStringAsync("https://www.coderbusy.com");
class NetEventListener : EventListener
protected override void OnEventSourceCreated(EventSource eventSource)
if (eventSource.Name.StartsWith("System.Net"))
EnableEvents(eventSource, EventLevel.Informational);
protected override void OnEventWritten(EventWrittenEventArgs eventData)
if (eventData.EventName == "ResolutionStart")
Console.WriteLine(eventData.EventName + " - " + eventData.Payload[0]);
else if (eventData.EventName == "RequestStart")
Console.WriteLine(eventData.EventName + " - " + eventData.Payload[1]);
当您运行此应用程序时,您应该会看到应用程序何时执行 http 请求和 DNS 请求:
RequestStart - www.coderbusy.com
ResolutionStart - www.coderbusy.com
RequestStart - www.coderbusy.com
RequestStart - www.coderbusy.com
RequestStart - www.coderbusy.com
RequestStart - www.coderbusy.com
RequestStart - www.coderbusy.com
RequestStart - www.coderbusy.com
ResolutionStart - www.coderbusy.com
以上是关于如何避免 .NET 中 HttpClient 的 DNS 失效问题?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 .net 和 .net 核心中使用 HttpClient 调用多个客户端 API
如何在使用 HttpClient 使用 Asp Net Web Api 的 Asp Net Mvc 中提供实时数据?