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


当前回答

你需要这样做:

    HttpContent httpContent = new StringContent(@"{ the json string }");
    httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));                
    HttpResponseMessage message = client.PostAsync(@"{url}", httpContent).Result;

其他回答

微软似乎试图强迫开发人员遵循他们的标准,甚至没有提供任何选项或设置,特别是考虑到这是一个客户端,我们是由服务器端需求决定的,特别是考虑到微软服务器端框架本身需要它!

所以基本上微软试图强迫我们养成好习惯,当连接到他们的服务器技术时,强迫我们养成不好的习惯……

如果微软的任何人正在阅读这篇文章,那么请修复它…

无论哪种方式,对于任何需要Get等内容类型头的人来说,在旧的。net版本中,可以在https://stackoverflow.com/a/41231353/640195上使用@erdomke的答案,不幸的是,这在新的。net核心版本中不再适用。

下面的代码经过测试,可以与。net core 3.1一起工作,从GitHub上的源代码来看,它应该也可以与更新的。net版本一起工作。

private void FixContentTypeHeaders()
{
    var assembly = typeof(System.Net.Http.Headers.HttpRequestHeaders).Assembly;
    var assemblyTypes = assembly.GetTypes();

    var knownHeaderType = assemblyTypes.FirstOrDefault(n => n.Name == "KnownHeader");
    var headerTypeField = knownHeaderType?
                .GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
                .FirstOrDefault(n => n.Name.Contains("HeaderType"));
    if (headerTypeField is null) return;

    var headerTypeFieldType = headerTypeField.FieldType;            
    var newValue = Enum.Parse(headerTypeFieldType, "All");

    var knownHeadersType = assemblyTypes.FirstOrDefault(n => n.Name == "KnownHeaders");
    var contentTypeObj = knownHeadersType.GetFields().FirstOrDefault(n => n.Name == "ContentType").GetValue(null);

    if (contentTypeObj is null) return;

    headerTypeField.SetValue(contentTypeObj, newValue);
}

如果你不介意一个小的库依赖,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

对于我的场景,第三方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());

调用AddWithoutValidation而不是Add(参见MSDN链接)。

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

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

我有一个非常特殊的情况,服务提供商不接受字符集,他们拒绝改变子结构来允许它…… 不幸的是,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");