提问



我试图按照我调用的API的要求设置HttpClient对象的Content-Type标题。


我尝试设置Content-Type如下所示:


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请求中设置Content-Type标题?

最佳参考


内容类型是内容的标题,而不是请求的标题,这就是失败的原因。 AddWithoutValidation如Robert Levy所建议的那样可以工作,但您也可以在创建请求内容时设置内容类型(请注意,代码片段在两个位置添加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);
      });

其它参考1


对于那些没有看到约翰斯对卡洛斯解决方案发表评论的人......


req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

其它参考2


如果你不介意一个小的库依赖,Flurl.Http [[披露:我是作者]]使这个简单。它的PostJsonAsync方法负责序列化内容和设置content-type标题,ReceiveJson反序列化响应。如果需要accept标题,你需要自己设置,但Flurl也提供了一种非常干净的方法:[43]


using Flurl.Http;

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


Flurl使用HttpClient和Json.NET,它是一个PCL,因此它可以在各种平台上运行。


PM> Install-Package Flurl.Http

其它参考3


尝试使用TryAddWithoutValidation


  var client = new HttpClient();
  client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");

其它参考4


调用AddWithoutValidation而不是Add(参见此MSDN链接)。[44]


或者,我猜你正在使用的API实际上只需要POST或PUT请求(不是普通的GET请求)。在这种情况下,当你调用HttpClient.PostAsync并传入HttpContent时,设置这个HttpContent对象的Headers属性。

其它参考5


.Net试图强迫您遵守某些标准,即Content-Type标题只能在具有内容的请求上指定(例如POSTPUT等。因此,正如其他人所指出的那样,设置Content-Type标题的首选方法是通过HttpContent.Headers.ContentType属性。[45]


话虽如此,某些API(例如LiquidFiles Api,截至2016-12-19)需要为GET请求设置Content-Type标头。 .Net不允许在请求本身上设置此标头 - 即使使用TryAddWithoutValidation。此外,您不能为请求指定Content - 即使它是零长度。我似乎唯一能解决这个问题的方法就是采取反思。代码(如果其他人需要它)是[46]


var field = typeof(System.Net.Http.Headers.HttpRequestHeaders)
    .GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) 
  ?? typeof(System.Net.Http.Headers.HttpRequestHeaders) 
    .GetField("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
if (field != null)
{
  var invalidFields = (HashSet<string>)field.GetValue(null);
  invalidFields.Remove("Content-Type");
}
_client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml");





如评论中所述,该字段在dll的不同版本中具有不同的名称。在GitHub的源代码中,该字段当前名为s_invalidHeaders。根据@David Thompson的建议修改了这个例子。[47]

其它参考6


关于.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;


并且,正如预期的那样,我得到了内容"Cannot send a content-body with this verb-type."的汇总异常


但是,如果我使用.NET Core(1.1)做同样的事情 - 我没有得到例外。我的服务器应用程序非常愉快地回答了我的请求,并且内容类型已被选中。


我对此感到惊喜,我希望它对某人有所帮助!

其它参考7


var content = new HttpContent();
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("charset", "utf-8"));
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("IEEE754Compatible", "true"));


这就是你需要的一切。

其它参考8


好吧,它不是HTTPClient,但如果你可以使用它,WebClient很容易:


using (var client = new System.Net.WebClient())
 {
    client.Headers.Add("Accept", "application/json");
    client.Headers.Add("Content-Type", "application/json; charset=utf-8");
    client.DownloadString(...);
 }