更新添加为HttpClient的DefaultRequestHeaders的自定义标头值

21

我有一个在多个请求中共享的静态httpclient,我想向其中添加一个自定义标头。

httpClient.DefaultRequestHeaders.Add("customHeader", somevalue.ToString());

但我注意到每次请求时该值都会添加到我想要在每个请求上替换的头部。我试图删除已经存在的标题并重新添加,但在负载测试中出现了错误。

if (httpClient.DefaultRequestHeaders.Contains("customHeader"))
        {
            httpClient.DefaultRequestHeaders.Remove("customHeader");
        }
httpClient.DefaultRequestHeaders.Add("customHeader",somevalue.ToString());

错误 -

System.ArgumentException: An item with the same key has already been added.
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
System.ArgumentNullException: Value cannot be null.

我如何在每个请求中更新自定义标头的值?


1
不要将其添加到“DefaultRequestHeaders”,而是添加到实际的请求中? - Icepickle
3
同时(并发)使用HttpClient.DefaultRequestHeaders对象会导致问题。您应该通过HttpRequestMessage来管理标头。 - levent
我建议您不要使用共享静态变量。静态变量在线程之间共享,会导致并发问题。我不使用静态httpclient。这个问题已经解决了。 - funbrain9
@funbrain9,你对此有何看法?相反,重用套接字是一个好的方法 https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ - anatol
4个回答

7

我遇到的错误是:已添加具有相同键的项目。 键:x

马赫什·英格回答提供的示例代码:

var request = new HttpRequestMessage
{
    Method = this.method,
    RequestUri = new Uri(this.requestUri),
};

request.Headers.Add("Key", "Value");

var client = new System.Net.Http.HttpClient
{
    Timeout = this.timeout
};

return await client.SendAsync(request);

5

我使用HttpRequestMessage向当前请求添加了头信息,并将调用替换为SendAsync而不是GetAsync,这样解决了我的问题。感谢@levent。


5

我遇到了与httpClient默认请求头相同的问题。 请参见以下示例,使用HttpRequestMessage.headers代替。

 _httpClient.DefaultRequestHeaders.Clear();
 _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));

        XDocument requestXml = JsonConvert.DeserializeXNode(message.ToString());

        HttpRequestMessage webRequest = new HttpRequestMessage()
        {
            Content = new StringContent(requestXml.Document.ToString().Replace("\r\n", string.Empty), Encoding.UTF8, "text/xml"),
            Method = HttpMethod.Post,
            RequestUri = new Uri(uri),
        };
        webRequest.Headers.Add("CorrelationId", correlationId);
        webRequest.Headers.Add("SOAPAction", endpointSOAPAction);

以前我使用默认的请求头来进行 correlationid 和 soap action。


1

在决定如何为HttpClient分配Headers时,请考虑Headers是否对每个请求都相同,尤其是如果HttpClient实例在所有线程之间共享。

如果Headers始终相同,则可以使用DefaultRequestHeaders,并且只需要分配一次。

对DefaultRequestHeaders进行的任何更改都将影响访问该实例的所有线程。

下面的示例适用于.NET Core和.NET 7:

// include dependencies
using System.Linq;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

// check header has not already been set
if (!_httpClient.DefaultRequestHeaders.Contains("key"))
{
    _httpClient.DefaultRequestHeaders.Add("key", "value");
}

// test value exists
var headerValue = string.Empty;
    
if (_httpClient.DefaultRequestHeaders.Contains("key"))
{
    headerValue = _httpClient.DefaultRequestHeaders.GetValues("key").First();
}

// any other configuration...

// invoke the request using GetAsync
var response = await _httpClient.GetAsync("path");

var returnValue = string.Empty;

if (response.IsSuccessStatusCode)
{
    returnValue = await response.Content.ReadAsStringAsync();
}

然而,如果每个消息的标题都预计会更改,则应该在初始化每个新请求时设置一个HttpRequestMessage实例,并使用所需的值。

// include dependencies
using System.Linq;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

// use shared single instance to avoid port exhaustion in constructor etc.
_httpClient = new HttpClient();

// media-type accept header only needs to be assigned once
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

// initialize request
_httpClient.BaseAddress = new Uri("https://example.com/");

var headersDictionary = new Dictionary<string, string>()
                        {
                            {"key1", "value1"},
                            {"key2", "value2"}
                        };

// create instance of HttpRequestMessage
var httpRequestMessageObject = new HttpRequestMessage(HttpMethod.Get, "relativePath");

var body = "content";

httpRequestMessageObject.Content = new StringContent(body, Encoding.UTF8, "application/json");

// check keys are not duplicated
foreach (var header in headersDictionary)
{
    if (!httpRequestMessageObject.Headers.Contains(header.Key))
    {
        httpRequestMessageObject.Headers.Add(header.Key, header.Value);
    }
}

// test value exists
var headerValue = string.Empty;

if (httpRequestMessageObject.Headers.Contains("key"))
{
    headerValue = httpRequestMessageObject.Headers.GetValues("key").First();
}

// invoke the request using SendAsync
var response = await _httpClient.SendAsync(httpRequestMessageObject);

var returnValue = string.Empty;

if (response.IsSuccessStatusCode)
{
    returnValue = await response.Content.ReadAsStringAsync();
}

参考资料

以下是一些 Stack Overflow 答案,进一步说明了这一点:

  1. https://dev59.com/n1oU5IYBdhLWcg3wAjcs#37929393
  2. https://dev59.com/72gv5IYBdhLWcg3wVPTU#10679340

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接