我试图设置一个HttpClient对象的Content-Type头作为我调用的API所要求的。

我试着像下面这样设置内容类型:

using (var httpClient = new HttpClient())
{
    httpClient.BaseAddress = new Uri("http://example.com/");
    httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
    httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json");
    // ...
}

它允许我添加Accept头,但当我尝试添加Content-Type时,它会抛出以下异常:

误用头名称。确保请求头与一起使用 HttpRequestMessage,带有HttpResponseMessage的响应头,以及 内容头与HttpContent对象。

如何在HttpClient请求中设置内容类型报头?


当前回答

内容类型是内容的头,而不是请求的头,这就是失败的原因。Robert Levy建议的AddWithoutValidation可以工作,但是你也可以在创建请求内容本身时设置内容类型(注意,代码片段在两个地方添加了application/json - Accept和content - type头):

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://example.com/");
client.DefaultRequestHeaders
      .Accept
      .Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress");
request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}",
                                    Encoding.UTF8, 
                                    "application/json");//CONTENT-TYPE header

client.SendAsync(request)
      .ContinueWith(responseTask =>
      {
          Console.WriteLine("Response: {0}", responseTask.Result);
      });

其他回答

为那些受困于字符集的人准备的

我有一个非常特殊的情况,服务提供商不接受字符集,他们拒绝改变子结构来允许它…… 不幸的是,HttpClient通过StringContent自动设置报头,不管你传递的是null还是Encoding。UTF8,它总是会设置字符集…

今天我在改变子系统的边缘;从HttpClient转向其他东西,我想到了一些东西…,为什么不用反射来清空“字符集”呢?... 在我尝试之前,我想到了一种方法,“也许我可以在初始化后改变它”,这是有效的。

下面是如何设置“application/json”头没有“;charset = utf - 8”。

var jsonRequest = JsonSerializeObject(req, options); // Custom function that parse object to string
var stringContent = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
stringContent.Headers.ContentType.CharSet = null;
return stringContent;

注意:下面的空值无效,加";charset = utf - 8”

return new StringContent(jsonRequest, null, "application/json");

EDIT

@DesertFoxAZ建议也可以使用下面的代码,工作良好。(没有自己测试,如果它的工作率,并在评论中赞扬他)

stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

如果你不介意一个小的库依赖,Flurl。Http[披露:我是作者]使这个超级简单。它的PostJsonAsync方法负责序列化内容和设置内容类型报头,而ReceiveJson则反序列化响应。如果accept头是必需的,你需要自己设置,但Flurl提供了一个非常干净的方式来做到这一点:

using Flurl.Http;

var result = await "http://example.com/"
    .WithHeader("Accept", "application/json")
    .PostJsonAsync(new { ... })
    .ReceiveJson<TResult>();

Flurl使用HttpClient和Json。它是一个PCL,所以它可以在各种平台上工作。

PM> Install-Package Flurl.Http

一些关于。net Core的额外信息(在阅读了erdomke关于设置私有字段以在没有内容的请求上提供内容类型的文章后)…

在调试我的代码之后,我无法通过反射看到要设置的私有字段-所以我想我应该尝试重新创建这个问题。

我使用。net 4.6尝试了以下代码:

HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, @"myUrl");
httpRequest.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");

HttpClient client = new HttpClient();
Task<HttpResponseMessage> response =  client.SendAsync(httpRequest);  //I know I should have used async/await here!
var result = response.Result;

正如预期的那样,我得到了一个聚合异常,其内容为“无法发送具有此动词类型的内容体”。

然而,如果我用。net Core(1.1)做同样的事情-我不会得到异常。我的服务器应用程序非常高兴地回答了我的请求,并选择了内容类型。

我对此感到惊喜,我希望它能帮助到一些人!

我发现下面的方法最简单易懂:

async Task SendPostRequest()
{
    HttpClient client = new HttpClient();
    var requestContent = new StringContent(<content>);
    requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    var response = await client.PostAsync(<url>, requestContent);
    var responseString = await response.Content.ReadAsStringAsync();
}
...

SendPostRequest().Wait();

对于那些想要专门将Content-Type设置为Json的人,你可以使用扩展方法PostAsJsonAsync。

using System.Net.Http.Json; //this is needed for PostAsJsonAsync to work
//....
HttpClient client = new HttpClient();
HttpResponseMessage response = await
    client.PostAsJsonAsync("http://example.com/" + "relativeAddress",
                new
                {
                    name = "John Doe",
                    age = 33
                });
//Do what you need to do with your response

这样做的好处是代码更简洁,并且可以避免字符串化的json。更多详情请访问:https://learn.microsoft.com/en-us/previous-versions/aspnet/hh944339(v=vs.118)