我试图设置一个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请求中设置内容类型报头?


当前回答

尝试使用HttpClientFactory

services.AddSingleton<WebRequestXXX>()
        .AddHttpClient<WebRequestXXX>("ClientX", config =>
        {
           config.BaseAddress = new System.Uri("https://jsonplaceholder.typicode.com");
           config.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
           config.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
        });

======================

public class WebRequestXXXX
{
    private readonly IHttpClientFactory _httpClientFactory;

    public WebRequestXXXX(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public List<Posts> GetAllPosts()
    {
        using (var _client = _httpClientFactory.CreateClient("ClientX"))
        {
            var response = _client.GetAsync("/posts").Result;

            if (response.IsSuccessStatusCode)
            {
                var itemString = response.Content.ReadAsStringAsync().Result;
                var itemJson = System.Text.Json.JsonSerializer.Deserialize<List<Posts>>(itemString, 
                    new System.Text.Json.JsonSerializerOptions 
                    {
                        PropertyNameCaseInsensitive = true
                    });

                return itemJson;
            }
            else
            {
                return new List<Posts>();
            }
        }
    }
}

其他回答

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();
    }
}

我也有类似的问题。 所以我发现Software PostMan可以在点击左上角的“code”按钮时生成代码。从中我们可以看到在“引擎盖下”发生了什么,HTTP调用是用许多代码语言生成的;curl命令,c# RestShart, java, nodeJs,…

这对我帮助很大,而不是使用。net基础HttpClient,我最终使用RestSharp nuget包。

希望能帮助到其他人!

尝试使用TryAddWithoutValidation

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

如果你不介意一个小的库依赖,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试图强迫你遵守某些标准,即content - type头只能在有内容的请求上指定(例如POST, PUT等)。因此,正如其他人指出的那样,设置Content-Type报头的首选方法是通过HttpContent.Headers.ContentType属性。

话虽如此,某些Api(如截至2016-12-19的LiquidFiles Api)需要为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");

编辑:

正如注释中所指出的,该字段在不同版本的dll中有不同的名称。在GitHub的源代码中,该字段当前命名为s_invalidHeaders。这个例子已经根据@David Thompson的建议进行了修改。