初始化 HttpClient 的最佳实践

13 浏览
0 Comments

初始化 HttpClient 的最佳实践

这是一个虚构的场景,我想找到最佳实现方式,并了解最佳实践。\n我正在编写一个服务,该服务向需要授权头的API发出GET请求,问题是我为每个服务初始化一个新的客户端,我在思考是否最好使用单例客户端,并在不同的服务中使用它。\n这里有我的BlogService,我在这里初始化客户端,然后添加授权头,用户名和密码将在配置中,但这只是一个例子。\n代码如下:\n

namespace MyDemoProject.Services
{
  public class BlogService : IBlogService
  {
    private readonly HttpClient client;
    private string username = "myUsername";
    private string password = "myPassword";
    private static string url = "https://example.com/api/blogs";
    public BlogService()
    {
      client = new HttpClient();
      string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
      client.DefaultRequestHeaders.Add("Authorization", "Basic " + encoded);
    }
    public async Task GetAllBlogs()
    {
      var request = await client.GetAsync(url);
      var data = await request.Content.ReadAsStringAsync();
      return data;
    }
  }
}

\n这里是我的CommentService,非常相似,但是使用了不同的URL。这只是一个简单的例子,它可以包含在同一个BlogService中,但假设我希望将其分解以便于可维护性和可扩展性。\n代码如下:\n

namespace MyDemoProject.Services
{
  public class CommentService : ICommentService
  {
    private readonly HttpClient client;
    private string username = "myUsername";
    private string password = "myPassword";
    private static string url = "https://example.com/api/comments";
    public CommentService()
    {
      client = new HttpClient();
      string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
      client.DefaultRequestHeaders.Add("Authorization", "Basic " + encoded);
    }
    public async Task GetAllComments()
    {
      var request = await client.GetAsync(url);
      var data = await request.Content.ReadAsStringAsync();
      return data;
    }
  }
}

\n是否有更好的实现方式?这种实现方式是否存在任何问题?

0
0 Comments

使用HttpClient的最佳实践是避免手动创建实例,因为这可能会导致DNS缓存和TCP连接未被回收而引起不必要的问题。

解决方法是使用HttpClientFactory,它会为您创建和维护HttpClient。

首先需要从nuget添加依赖Microsoft.Extensions.DependencyInjection

如果使用依赖注入,将以下代码添加到Startup文件中的ConfigureServices方法中:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<BearerTokenHandler>();
    services.AddHttpClient<ICommentService, CommentService>()
        .ConfigureHttpClient(client =>
        {
            client.BaseAddress = new Uri("https://example.com/api");
        })
        .AddHttpMessageHandler<BearerTokenHandler>();
}

然后,在MyDemoProject.Services命名空间下创建BearerTokenHandler类和CommentService类。

BearerTokenHandler类继承自DelegatingHandler,并重写SendAsync方法,用于添加身份验证头信息。

namespace MyDemoProject.Services
{
    public class BearerTokenHandler : DelegatingHandler
    {
        private const string BasicAuthenticationScheme = "Basic";
        private string username = "myUsername";
        private string password = "myPassword";
        public BearerTokenHandler()
        {
        }
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
            request.Headers.Authorization = new AuthenticationHeaderValue(BasicAuthenticationScheme, token);
            return await base.SendAsync(request, cancellationToken);
        }
    }
}

CommentService类实现了ICommentService接口,并在构造函数中注入HttpClient实例。

namespace MyDemoProject.Services
{
    public class CommentService : ICommentService
    {
        private readonly HttpClient client;
        public CommentService(HttpClient httpClient)
        {
            client = httpClient;
        }
        public async Task<string> GetAllComments()
        {
            string response = null;
            using (var request = new HttpRequestMessage(HttpMethod.GET, "comments"))
            {
                response = await client.SendAsync(request);
            }
            var data = await response.Content.ReadAsStringAsync();
            return data;
        }
    }
}

通过使用HttpClientFactory和依赖注入,可以更好地初始化和管理HttpClient,避免了手动创建HttpClient实例可能引起的问题。

0
0 Comments

在.NET 6中,最佳实践是使用IHttpClientFactory来避免每次使用HttpClient时都创建新的实例,以及避免代码重复。

以下是一个基于您的代码的简单示例。

首先,您需要注册和配置IHttpClientFactory,如下所示:

_ = services.AddHttpClient("MyHttpClientKey", (serviceProvider, httpClient) =>
{
   private string username = "myUsername";
   private string password = "myPassword";
   string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
   _ = httpClient.BaseAddress = new Uri("https://example.com/api/comments");
   _ = httpClient.Timeout = TimeSpan.FromSeconds(30);
   httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + encoded);
});

然后,您可以在类中注入HttpClient并使用它:

public class CommentService : ICommentService
{
    private readonly HttpClient client;
    public CommentService(IHttpClientFactory httpClientFactory)
    {
        httpClient = httpClientFactory.CreateClient("MyHttpClientKey");
    }
    public async Task GetAllComments()
    {
      var request = await client.GetAsync(url);
      var data = await request.Content.ReadAsStringAsync();
      return data;
    }
}

希望对您有所帮助!

0