首页 文章

如何为HttpClient请求设置Content-Type标头?

提问于
浏览
517

我正在尝试按照我调用的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 时,它会抛出以下异常:

未使用的 Headers 名称 . 确保请求标头与HttpRequestMessage一起使用,响应标头与HttpResponseMessage一起使用,内容标头与HttpContent对象一起使用 .

如何在 HttpClient 请求中设置 Content-Type 标头?

9 回答

  • 28

    关于.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)做同样的事情 - I don't get an exception. 我的服务器应用程序非常高兴地回答了我的请求,并且内容类型已被选中 .

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

  • 17

    内容类型是内容的 Headers ,而不是请求的 Headers ,这就是失败的原因 . 根据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);
          });
    
  • 1

    try to use TryAddWithoutValidation

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

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

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

    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");
    

    Edit:

    如评论中所述,该字段在dll的不同版本中具有不同的名称 . 在source code on GitHub中,该字段当前名为 s_invalidHeaders . 根据@David Thompson的建议,该示例已经过修改以解释此问题 .

  • 2

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

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

    好吧,它不是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(...);
     }
    
  • 13
    var content = new JsonContent();
    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"));
    

    这就是你需要的一切 .

    使用Newtonsoft.Json,如果你需要一个内容作为json字符串 .

    public class JsonContent : HttpContent
       {
        private readonly MemoryStream _stream = new MemoryStream();
        ~JsonContent()
        {
            _stream.Dispose();
        }
    
        public JsonContent(object value)
        {
            Headers.ContentType = new MediaTypeHeaderValue("application/json");
            using (var contexStream = new MemoryStream())
            using (var jw = new JsonTextWriter(new StreamWriter(contexStream)) { Formatting = Formatting.Indented })
            {
                var serializer = new JsonSerializer();
                serializer.Serialize(jw, value);
                jw.Flush();
                contexStream.Position = 0;
                contexStream.WriteTo(_stream);
            }
            _stream.Position = 0;
    
        }
    
        private JsonContent(string content)
        {
            Headers.ContentType = new MediaTypeHeaderValue("application/json");
            using (var contexStream = new MemoryStream())
            using (var sw = new StreamWriter(contexStream))
            {
                sw.Write(content);
                sw.Flush();
                contexStream.Position = 0;
                contexStream.WriteTo(_stream);
            }
            _stream.Position = 0;
        }
    
        protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            return _stream.CopyToAsync(stream);
        }
    
        protected override bool TryComputeLength(out long length)
        {
            length = _stream.Length;
            return true;
        }
    
        public static HttpContent FromFile(string filepath)
        {
            var content = File.ReadAllText(filepath);
            return new JsonContent(content);
        }
        public string ToJsonString()
        {
            return Encoding.ASCII.GetString(_stream.GetBuffer(), 0, _stream.GetBuffer().Length).Trim();
        }
    }
    
  • 653

    调用 AddWithoutValidation 而不是 Add (参见this MSDN link) .

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

  • 15

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

    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
    

相关问题