【问题标题】:C# HttpClient custom headers each requestC# HttpClient 自定义标头每个请求
【发布时间】:2019-05-24 18:06:29
【问题描述】:

我注意到在修改 HttpClient.DefaultRequestHeaders 时使用 HttpClient 不是线程安全的,但我想发出尽可能多的请求。 每个请求我都需要一个自定义标头(其他 2 个标头始终相同)。网址也发生了一些变化

  1. http://example.com/books/1234/readers/837
  2. http://example.com/books/854/readers/89
  3. http://example.com/books/29432/readers/238
  4. ... 以此类推

目前我正在为每个请求创建一个新的 HttpClient,但我觉得创建 10k+ HttpClient 并不是最好的选择。

我想制作一个带有 2 个 DefaultRequestHeaders 的静态 HttpClient,并为每个请求使用这个 HttpClient,但还要添加一个自定义标头。

我想尽可能快地完成这个,所以如果你有别的东西我会接受的。

        Parallel.ForEach(Requests, Request =>
        {
            var Client = new HttpClient();
            Client.DefaultRequestHeaders.Clear();
            Client.DefaultRequestHeaders.Add("Header1", "Value1");
            Client.DefaultRequestHeaders.Add("Header2", "Value2");
            Client.DefaultRequestHeaders.Add("Header3", "Value for exact this request");

            var response = Client.PutAsync(new Uri($"http://example.com/books/1234/readers/837"), null); //.Result (?)
            Client.Dispose();
        });

【问题讨论】:

    标签: c# request header httpclient


    【解决方案1】:

    不要将DefaultRequestHeaders 用于不适用于HttpClient 发送的所有请求的标头。

    另外,不要为每个请求创建 HttpClient。

    您可以通过为每个请求创建一个HttpRequestMessage,应用您需要的任何标头,并将相同的HttpClient 用于.SendAsync() 来轻松做到这一点:

    using (var request = new HttpRequestMessage(HttpMethod.Put, url)
    {
        request.Headers.<add here>;
        // optionally set .Content
    
        using (var response = await httpClient.SendAsync(request))
        {
            // ... process response
        }
    }
    

    【讨论】:

    【解决方案2】:

    我认为DelegatingHandler 的使用将能够完成您正在寻找的东西。您将停止使用 DefaultRequestHeaders,而是将它们设置在 DelegatingHandler 中。

    另外请注意,HttpClient 对请求是线程安全的,不应被丢弃。这是因为它处理了底层的HttpMessageHandler,这会导致一些较低级别的低效率。更多细节在这里http://www.nimaara.com/2016/11/01/beware-of-the-net-httpclient/。

    Sample.cs

    // .Net Framework, careful here because the sockets will be cached, network changes will break your app
    // see http://www.nimaara.com/2016/11/01/beware-of-the-net-httpclient/ for more details
    
    var client = new HttpClient(new MyCustomHandler() { InnerHandler = new HttpClientHandler() });
    
    // .Net Core
    client = new HttpClient(new MyCustomHandler() { InnerHandler = new SocketsHttpHandler() { PooledConnectionLifetime = TimeSpan.FromMinutes(1) } });
    
    Parallel.ForEach(Requests, Request =>
    {
    
        var response = client.PutAsync(new Uri($"http://example.com/books/1234/readers/837"), null); //.Result (?)
    
        // do not dispose of httpclient!
    });
    

    MyCustomHandler.cs

    public class MyCustomHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // the static headers
            request.Headers.Add("Header1", "Value1");
            request.Headers.Add("Header2", "Value2");
    
            // the unique header
            SignRequest(request);
    
            return base.SendAsync(request, cancellationToken);
        }
    
    
        public void SignRequest(HttpRequestMessage message)
        {
            // usually the pattern of a unique header per request is for an authorization header based on some signature of the request
            // this logic would be here
            // generate the signature
            string signature = new Random().Next(int.MaxValue).ToString();
    
            message.Headers.Add("Header3", signature);
        }
    }
    

    【讨论】:

      【解决方案3】:

      .NET Core 2.1 起使用 HttpClient 的标准场景是:

      直接传递所有标头且无需批处理的简单示例:

      var tasks = Enumerable.Range(1, 10000)
          .Select(v => HttpClientFactory.Create().SendAsync(new HttpRequestMessage(HttpMethod.Put, new Uri($"http://example.com/books/1234/readers/837"))
          {
              Headers =
              {
                  {"Header1", "Value1"},
                  {"Header2", "Value2"},
                  {"Header3", v.ToString()},
              },
              Content = new StringContent("{test:\"hello\"}", Encoding.UTF8, "application/json")
          }));
      
      var responses = await Task.WhenAll(tasks).ConfigureAwait(false);
      // ..
      

      备注:

      • 发送数千个请求看起来很可疑,你确定那个服务器 没有用于分组处理项目的端点
      • 使用 PLINQ 对于非 CPU 消耗任务不正确(引用:“PLINQ 查询根据功能扩展并发程度 主机”)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-24
        • 1970-01-01
        • 2014-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        相关资源
        最近更新 更多