C#HttpClient自定义标头的每个请求

时间:2019-05-24 18:06:29

标签: c# request header httpclient

我注意到在修改 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 + HttpClients不是这里的最佳选择。

我想用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();
        });

3 个答案:

答案 0 :(得分:0)

从.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 查询根据功能的并发程度进行扩展 主机”)

答案 1 :(得分:0)

我认为DelegatingHandler的使用将能够完成您所需要的。您将停止使用DefaultRequestHeaders,而是在DelegatingHandler中进行设置。

还请注意,HttpClient对于请求是线程安全的,不应丢弃。这是因为它处理了底层HttpMessageHandler,而底层Sample.cs会导致较低级别的效率低下。更多详细信息,请参见http://www.nimaara.com/2016/11/01/beware-of-the-net-httpclient/

// .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); } }

{{1}}

答案 2 :(得分:0)

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

此外,请勿为每个请求创建一个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
    }
}