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


当前回答

. 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的建议进行了修改。

其他回答

尝试使用TryAddWithoutValidation

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

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

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

希望能帮助到其他人!

对于我的场景,第三方API正在创建HttpRequestMessage,因此我无法使用投票最多的答案来解决这个问题。我不喜欢干扰反射的想法所以其他答案也不成立。

相反,我从AndroidMessageHandler扩展,并使用这个新类作为HttpClient的参数。AndroidMessageHandler包含SendAsync方法,可以在HttpRequestMessage对象发送之前重写该方法。如果您没有访问Android Xamarin库的权限,您可以使用HttpMessageHandler来解决一些问题。

public class XamarinHttpMessageHandler : global::Xamarin.Android.Net.AndroidMessageHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Here I make check that I'm only modifying a specific request
        // and not all of them.
        if (request.RequestUri != null && request.RequestUri.AbsolutePath.EndsWith("download") && request.Content != null)
        {
            request.Content.Headers.Add("Content-Type", "text/plain");
        }
        return base.SendAsync(request, cancellationToken);
    }
}

然后使用:

var client = new HttpClient(new XamarinHttpMessageHandler());

一些关于。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)做同样的事情-我不会得到异常。我的服务器应用程序非常高兴地回答了我的请求,并选择了内容类型。

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

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