C # HttpClient пользовательских заголовков каждый запрос - PullRequest
1 голос
/ 24 мая 2019

Я заметил, что использование HttpClient НЕ потокобезопасен при изменении HttpClient.DefaultRequestHeaders , но я хочу сделать как можно больше запросов.Мне нужен собственный заголовок каждого запроса (2 других заголовка всегда одинаковы).Также URL меняется немного

  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 + HttpClients здесь не лучший выбор.

Я хотел бы создать один статический HttpClient с 2 DefaultRequestHeaders.и используйте этот 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();
        });

Ответы [ 3 ]

0 голосов
/ 24 мая 2019

Я думаю, что использование 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);
    }
}
0 голосов
/ 24 мая 2019

Не используйте 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
    }
}
0 голосов
/ 24 мая 2019

Стандартный сценарий использования HttpClient начиная с .NET Core 2.1:

  • создать его через HttpClientFactory
  • пользовательские заголовки, передаваемые в теле запросов (фиксированные заголовки могут быть определено в обычай DelegatingHandler )

Простой пример с прямой передачей всех заголовков и без пакетной обработки:

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 для задач, не потребляющих процессор, некорректна (цитата: "PLINQ масштабирование запросов в степени параллелизма на основе возможностей хост-компьютера ")
...