【问题标题】:how to use a static instance of HttpClient with multiple consumers如何将 HttpClient 的静态实例与多个消费者一起使用
【发布时间】:2019-08-08 21:31:35
【问题描述】:

我们如何重用 HttpClient 的静态实例?

我有一个静态的HttpClient,我想同时重用它:

    private static HttpClient client = new HttpClient();

我正在这样创建我的请求:

            var attachTopic = GetEnvironmentVariable("Attach:EventTopicUri");
            var attachTopicKey = GetEnvironmentVariable("Attach:EventTopicKey");
            client.BaseAddress = new Uri(attachTopic);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Add("aeg-sas-key", attachTopicKey);

然后发布请求:

await client.PostAsJsonAsync("", new[] { /*some awesome object*/ });

但是,我遇到了以下问题:

我们如何在静态 HttpClient 上发出具有相同标头信息的并发请求?

【问题讨论】:

  • 你不能像BaseAddressclient.DefaultRequestHeaders.Accept.Clear(); 这样跨多个并发请求设置属性。我建议设置一次DefaultRequestHeaders(在启动时),而不是设置BaseAddress。或者,在由string 键入的字典中具有单独的HttpClient 对象。然后将多个共享客户端放在那里,每个客户端都有不同的BaseAddress
  • 如果您使用 .NET Core,HttpClientFactory 将为每个 BaseAddress 返回静态 HttpClients,并在 DNS 解析发生变化时更新连接。
  • 在@mjwills 评论的基础上,您的BaseAddress 也应该是您发送请求的域,它不应该在请求之间更改,您在GetAsync 中使用的请求URL 将更改为那就是您从域中请求的路径/资源。如果域不同,那么它们就是不同的 HttpClient 实例,每个域都可以重复使用,正如 Dour High Arch 指出的那样。

标签: c# .net httpclient azure-functions


【解决方案1】:

我建议你在你的项目中引入依赖注入。可以看官方文档HERE

文档中的第一个示例将HttpClient 添加到服务提供者:

public override void Configure(IFunctionsHostBuilder builder)
{
    builder.Services.AddHttpClient();
    builder.Services.AddSingleton((s) => {
        return new CosmosClient(Environment.GetEnvironmentVariable("COSMOSDB_CONNECTIONSTRING"));
    });
    builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
}

要使用您的 HttpClient,您必须将其注入到您的函数类构造函数中:

public class MyFunc
{
    private readonly HttpClient _client;

    public MyFunc(IHttpClientFactory httpClientFactory)
    {
        _client = httpClientFactory.CreateClient();
    }

    [FunctionName("DoSomething")]
    public async Task<IActionResult> Get(
        [HttpTrigger(AuthorizationLevel.Function, "get", Route = "do-something")] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");
        var res = await _client.GetAsync("my-cool-url.com);

        return new OkResult(res);
   }
}

我特别喜欢这种方法的一点是,当您将其注册到 DI 时,您可以创建不同的键控客户端:

private void ConfigureService(IWebJobBuilder builder)
{
    // Some logic
    builder.Services.AddHttpClient("aaa", client =>
    {
        client.BaseAddress = new Uri("base-address.com");
    });
}

然后像这样使用它:

public MyFunc(IHttpClientFactory httpClientFactory)
{
    _client = httpClientFactory.CreateClient("aaa");
}

如果有什么不适合你的,请告诉我。 :)

【讨论】:

  • 这是正确的做法。
  • 在这种情况下你会如何设置标题? DefaultRequestHeader.Add 应该只用于客户端的实例化。
  • 那是一个完全不同的答案。在极少数情况下,我建议设置默认请求标头。恕我直言,正确的方法是使用 Http 处理程序为每个请求添加标头。但是,如果您坚持初始化默认标头,您可以在配置部分添加它们。检查我的答案中的方法 ConfigureService 。就像我在那里设置一个 BaseAddress 一样,你可以在那里设置你想要的任何其他值,并且它只会在初始化实例时发生一次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多