我应该缓存和重用从HttpClientFactory创建的HttpClient吗?

时间:2019-02-08 17:13:09

标签: c# .net-core httpclient dotnet-httpclient

我们可以在这里YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE读到,我们不应该为每个http请求创建和处置HttpClient。相反,应该对其进行缓存和重用(例如,作为DI容器中的Singleton)。以及HttpClient的.NET官方文档中:

HttpClient旨在实例化一次,并在应用程序的整个生命周期内重复使用。为每个请求实例化HttpClient类将耗尽繁重负载下可用的套接字数量。这将导致SocketException错误。下面是正确使用HttpClient的示例。

建议使用HttpClientFactory,但在查看之后:

  public interface IHttpClientFactory
  {
    /// <summary>
    /// Creates and configures an <see cref="T:System.Net.Http.HttpClient" /> instance using the configuration that corresponds
    /// to the logical name specified by <paramref name="name" />.
    /// </summary>
    /// <param name="name">The logical name of the client to create.</param>
    /// <returns>A new <see cref="T:System.Net.Http.HttpClient" /> instance.</returns>
    /// <remarks>
    /// <para>
    /// Each call to <see cref="M:System.Net.Http.IHttpClientFactory.CreateClient(System.String)" /> is guaranteed to return a new <see cref="T:System.Net.Http.HttpClient" />
    /// instance. Callers may cache the returned <see cref="T:System.Net.Http.HttpClient" /> instance indefinitely or surround
    /// its use in a <langword>using</langword> block to dispose it when desired.
    /// </para>
    /// <para>
    /// The default <see cref="T:System.Net.Http.IHttpClientFactory" /> implementation may cache the underlying
    /// <see cref="T:System.Net.Http.HttpMessageHandler" /> instances to improve performance.
    /// </para>
    /// <para>
    /// Callers are also free to mutate the returned <see cref="T:System.Net.Http.HttpClient" /> instance's public properties
    /// as desired.
    /// </para>
    /// </remarks>
    HttpClient CreateClient(string name);
  }

它说每个调用将始终创建一个HttpClient实例,并且调用者可以对其进行缓存。

每次调用IHttpClientFactory.CreateClient都会保证返回一个新的HttpClient 实例。调用者可以无限期缓存或环绕返回的实例

所以问题是我应该完全依靠 HttpClientFactory 还是应该缓存从中创建的 HttpClient

在我们的项目中,每次发出请求时,我们都会使用 HttpClientFactory.CreateClient ,他仍然会有套接字异常。

2 个答案:

答案 0 :(得分:4)

HttpClient仅是IDisposable,因为其HttpMessageHandlerIDisposable。实际上,HttpMessageHandler应该是长寿的。

HttpClientFactory通过在内部保留一个寿命长的HttpMessageHandler来工作。每当您要求使用HttpClient时,它都会使用寿命长的HttpMessageHander,并在HttpClient被使用时告诉HttpClient not 进行处置。处置。

您可以看到on GitHub

public HttpClient CreateClient(string name)
{
    // ...

    // Get a cached HttpMessageHandler
    var handler = CreateHandler(name);

    // Give it to a new HttpClient, and tell it not to dispose it
    var client = new HttpClient(handler, disposeHandler: false);

    // ...

    return client;
}

因此,从技术上讲,缓存HttpClient还是立即处置并不重要-处置它不会做任何事情(因为有人告诉您不要处置其HttpClientHandler,因为由HttpClientFactory管理。

关于处置HttpClientMSDN says

  

不需要处理客户端。 Disposal取消传出的请求,并确保在调用Dispose之后不能使用给定的HttpClient实例。 IHttpClientFactory跟踪并处置HttpClient实例使用的资源。 HttpClient实例通常可以视为不需要处理的.NET对象。

     

在IHttpClientFactory建立之前,通常使用一个长期的单个HttpClient实例。迁移到IHttpClientFactory后,该模式就不再需要。

我怀疑您看到的SocketException是有不同的原因。也许问一个针对他们的新问题?

答案 1 :(得分:1)

#source file location path = "myfile.csv" # define column location and then define the width column_locations = np.array([1, 25, 30, 31, 47, 58, 75, 92, 109, 126, 132, 152, 158, 163, 179, 190, 207, 224, 241, 258, 264, 295, 311, 322, 356, 373 ]) widths = column_locations[1:] - column_locations[:-1] #creating numpy array from the source file data = np.genfromtxt(path, dtype=None, delimiter=widths, autostrip=True) print(data) data =np.char.replace(data,',',' ') np.savetxt(path,data,delimiter=",",fmt='%s') 版本中,情况发生了很大的变化。 ASP.NET Core 2.2的使用方式仅是通过DI进行的,DI使用HttpClient在内部为您处理所有必需的缓存。以下文档文章已更新,以反映这些新用例:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2

另外,来自ASP.NET Core团队的@RyanNowak在以下ASP.Net Core社区站立会议中介绍了所有这些更改:https://www.youtube.com/watch?v=Lb12ZtlyMPg 如果您还没有看过,我强烈建议您观看,因为它具有丰富的信息和教育意义。

这里有一个小样本来展示用法。在HttpClientFactory方法调用中:

Startup.ConfigureServices

注意:存在多种使用模式,这是最基本的一种。在文档中查找其他模式,可以更好地满足您的需求。

稍后,在该类中,您要从其发出http请求,请对services.AddHttpClient(); 进行依赖,然后让DI必要时为您实例化它。这是Microsoft Docs的示例:

IHttpClientFactory