自定义 HttpClient 请求头

231

我该如何在HttpClient请求中添加自定义标头? 我正在使用PostAsJsonAsync方法发布JSON。 我需要添加的自定义标头是

"X-Version: 1"

这是我目前为止所做的:

using (var client = new HttpClient()) {
    client.BaseAddress = new Uri("https://api.clickatell.com/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "xxxxxxxxxxxxxxxxxxxx");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    var response = client.PostAsJsonAsync("rest/message", svm).Result;
}

@Liam:我的问题是如何添加自定义标头。而另一个问题是如何添加标头。 - Libin Joseph
6
我认为已经有人发现我们不应该丢弃 HttpClient。原文链接:https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ - Don Rolling
9个回答

307

我已经找到了我的问题的答案。

client.DefaultRequestHeaders.Add("X-Version","1");

那应该会向您的请求添加自定义标题


93
不,它并没有。这个答案应该谨慎查看,因为默认的请求头会随着每个请求一起发送。您应该像@Anubis建议的那样构建您的请求。在创建HttpClient时应填写DefaultsRequestHeaders。 - Ruhrpottpatriot
17
这仅在每个请求实例化一个新的HttpClient时才起作用。这不是应该使用该类的方式:它应该是一个静态字段,为所有请求重复使用,至少对于相同的端点请求。请参阅文档和无数博客文章。然后,正如@Ruhrpottpatriot所指出的那样,更改默认标头将影响所有请求。 - kamilk
2
@ajbeaven 不是这样的。页面顶部的示例显示了应用程序的Main方法,因此即使HttpClient被处理掉,同一实例仍将在应用程序的整个生命周期中使用,这符合文档稍后所说的:“HttpClient旨在被实例化一次并在应用程序的整个生命周期中重复使用”。在本段之后,有一个示例建议将HttpClient分配给静态字段。 - kamilk
1
@kamilk,你说得对极了 - 那个例子让我误解了。感谢你纠正我 :) - ajbeaven
2
如果使用 HttpClientFactory 实例化 httpclient,那么使用这个答案可以吗? - Alex from Jitbit
显示剩余7条评论

166

这里是基于 Anubis 的回答(这是更好的方法,因为它不会修改每个请求的标头),但更等同于原始问题中的代码的答案:

using Newtonsoft.Json;
...

var client = new HttpClient();
var httpRequestMessage = new HttpRequestMessage
    {
        Method = HttpMethod.Post,
        RequestUri = new Uri("https://api.clickatell.com/rest/message"),
        Headers = { 
            { HttpRequestHeader.Authorization.ToString(), "Bearer xxxxxxxxxxxxxxxxxxx" },
            { HttpRequestHeader.Accept.ToString(), "application/json" },
            { "X-Version", "1" }
        },
        Content = new StringContent(JsonConvert.SerializeObject(svm))
    };

var response = client.SendAsync(httpRequestMessage).Result;

4
同意这个答案。它展示了如何添加 OP 请求的标题。同时也回答了我的问题。 - Ron
1
FYI,我认为 HttpRequestHeader.Access 应该是 HttpRequestHeader.Accept - Mass Dot Net
1
顺便问一下,SVM是什么? - aswzen
@aswzen 这是来自原帖的问题 - 我猜测是某个模型。被序列化的对象。 - Chris Peacock
1
@Alex 是的,同意。这只是一个自包含的例子,与 OP 的问题容易相关联。 - Chris Peacock
显示剩余5条评论

89
var request = new HttpRequestMessage {
    RequestUri = new Uri("[your request url string]"),
    Method = HttpMethod.Post,
    Headers = {
        { "X-Version", "1" } // HERE IS HOW TO ADD HEADERS,
        { HttpRequestHeader.Authorization.ToString(), "[your authorization token]" },
        { HttpRequestHeader.ContentType.ToString(), "multipart/mixed" },//use this content type if you want to send more than one content type
    },
    Content = new MultipartContent { // Just example of request sending multipart request
        new ObjectContent<[YOUR JSON OBJECT TYPE]>(
            new [YOUR JSON OBJECT TYPE INSTANCE](...){...}, 
            new JsonMediaTypeFormatter(), 
            "application/json"), // this will add 'Content-Type' header for the first part of request
        new ByteArrayContent([BINARY DATA]) {
            Headers = { // this will add headers for the second part of request
                { "Content-Type", "application/Executable" },
                { "Content-Disposition", "form-data; filename=\"test.pdf\"" },
            },
        },
    },
};

70
回答非常混乱...你为什么要引入文档、空白pdf等代码?实例化字节数组类以在Content参数中传递自定义标头? - heug
2
@heug 好的。如果你正在寻找头部,你可以看到它。内容在这里是为了完整图片,因为你很可能想要添加一些内容到你的请求中。为了不显得乏味,内容是复杂的,包含JSON和二进制数据。 - Anubis
2
似乎这样做更直接:使用你的内容JSON创建StringContent,使用你的方法和URI创建HTTP消息,然后添加头信息,如message.Headers.Add("x":"y")... 然后将它们传递到响应变量中,如"var response = await httpClient.SendAsync(message);"。 - heug
8
以上被接受的答案中,哪一行实际上实现了 OP 请求的 X-Version 头部?为什么这被认为是被接受的答案? - Ron
2
我发现这个答案非常有帮助,感谢提供额外的例子。 - Alex from Jitbit
显示剩余3条评论

9
在HttpRequestMessage类中有一个Headers属性。您可以在那里添加自定义标头,这些标头将随每个HTTP请求一起发送。另一方面,HttpClient类中的DefaultRequestHeaders设置了要使用该客户端对象发送的每个请求发送的标头,因此称为默认请求标头。
希望这能让事情更加清晰,至少对于看到此答案的某些人来说。

2
不,这并没有让它更清晰。在两种情况下,您都在说您正在发送每个请求的标头 - 那么有什么区别呢? - joedotnot
8
Headers是每个HttpRequestMessage对象自己的属性。因此,您可以创建带有不同 Headers 的不同消息。DefaultRequestHeadersHttpClient 对象的一个属性;如果通过给定的 HttpClient 发送多个消息,则所有这些消息都将添加相同的 DefaultRequestHeaders 到消息的各自 headers 中。 - Ross Presser

3
我已经在HttpClient头部中添加了x-api-version,如下所示:
var client = new HttpClient(httpClientHandler)
{
    BaseAddress = new Uri(callingUrl)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-version", v2);

2

此外,您还可以使用HttpClient.PostAsync方法:

using (HttpClient http_client = new HttpClient())
{
   StringContent string_content = new StringContent(JsonSerializer.Serialize("{\"field\":\"field_value\"}"));
   string_content.Headers.Add("X-Version","1");
   using (HttpResponseMessage response = await http_client.PostAsync("http://127.0.0.1/apiMethodName", string_content))
   {
      if (response.IsSuccessStatusCode)
      {
         Console.WriteLine($"Response status code: {response.StatusCode}");
      }
      else
      {
         Console.WriteLine($"Error status code: {response.StatusCode}");
      }
   }
}

1

我的建议是,我同意heug的观点。被接受的答案让人很困惑。我们来退一步。

默认标头适用于特定HttpClient发出的所有请求。因此,您可以使用默认标头来共享标头。

_client.DefaultRequestHeaders.UserAgent.ParseAdd(_options.UserAgent);          

然而,有时我们需要特定于某个请求的标头。因此,在该方法中,我们将使用以下内容:

public static async Task<HttpResponseMessage> GetWithHeadersAsync(this 
    HttpClient httpClient, string requestUri, Dictionary<string, string> headers)
    {
        using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
        {
            foreach(var header in headers)
            {
                request.Headers.Add(header.Key, header.Value);
            }

            return await httpClient.SendAsync(request);
        }
    }

如果您只需要一个非默认的额外标题,您可以简单地使用以下方式:
request.Headers.Add("X-Version","1")

更多帮助请参见:如何在使用HttpClient时添加请求头


0

如果有人想知道如何调用httpClient.GetStreamAsync(),但它没有重载以提供自定义标头的HttpRequestMessage,您可以使用@Anubis提供的上述代码并调用

await response.Content.ReadAsStreamAsync()

如果您返回带有Range Header的Blob URL作为FileStreamResult,这将非常有用。


0

您可以使用System.Net.Http.Json.JsonContent,它是PostAsJsonAsync()内部使用的:

var jsonContent = JsonContent.Create(payload);
jsonContent.Headers.Add("X-custom-header", "Value");

var resp = await httpClient.PostAsync(uri, jsonContent);

这种方法相比其他替代方案具有以下优点:

  • 它使用经过优化的UTF-8序列化,与应用程序配置的行为相匹配。
  • 它不会设置DefaultRequestHeaders,从而不会影响其他无关的查询。

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