在HttpClient中为Get操作显式设置Content-Type标头

14

当使用 HttpClient 进行 GET 请求时,有没有一种方法可以显式设置 Content-Type 头的值?我知道这会破坏 1.1 协议,但我正在使用一个不符合协议且要求我设置 Content-Type 头的 API。

我已经尝试过,但没有成功...

using (var httpClient = new HttpClient())
{
   var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://example.com");

   httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded+v1.3");

   await httpClient.SendAsync(httpRequestMessage)
}

在添加了TryAddWithoutValidation之后,我检查了DefaultRequestHeaders,但似乎没有设置Content-Type的值。

如果我尝试设置httpRequestMessage的Content-Type(通过设置httpRequestMessage.Content = ...),会出现以下错误:

Cannot send a content-body with this verb-type.

使用HttpClient发起GET请求时,是否有一种方法可以显式地设置Content-Type


作为一种解决方法,我目前已经能够使用“WebClient”。 - Nagoh
@ZenCoder。这不会设置“Content-Type”头。只有“Accept”头。 - Nagoh
GET操作没有请求体,因此不需要设置Content-Type。如果可能的话,应该纠正API。 - Suncat2000
5个回答

7

通过一些反射技巧和引入一个DelegatingHandler作为参数传递给HttpClient构造函数,可以覆盖库的行为。请参见下面的代码。

public class HmacAuthenticatingHandler : DelegatingHandler
{
    public HmacAuthenticatingHandler(HttpMessageHandler innerHandler) 
       : base(innerHandler)
    {
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {

        // HACK: Set 'Content-Type' even for GET requests
        var invalidHeaders = (HashSet<string>)typeof(HttpHeaders)
            // use "_invalidHeaders" for System.Net.Http v2.2+
            .GetField("invalidHeaders", BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(request.Headers);
        invalidHeaders.Remove("Content-Type");

        request.Headers.Remove("Content-Type");
        request.Headers.Add("Content-Type", "application/json");

        var response = await base.SendAsync(request, cancellationToken);
        return response;
    }
}

无法在 .Net Framework 版本 4.0、System.Net.Http 版本 2.2.29.0 上工作,但可以在 2.0.0.0 上工作。 - prem
1
@prem 将 "invalidHeaders" 更改为 "_invalidHeaders"。 - Andy

7
根据我的调查结果,我得出结论:HttpClient在协议规则方面非常严格。我还通过实现DLL进行了反思,但没有发现任何违反协议的迹象。
GET请求不应该有content-type头,而HttpClient正在执行此规则。
我认为当您尝试设置content-type头时,异常消息是自描述的:
System.InvalidOperationException: 错误的标头名称。确保使用HttpRequestMessage与请求标头,使用HttpResponseMessage与响应标头,并使用HttpContent对象与内容标头。
如果您设置内容主体,则会获得另一个自描述消息:
System.Net.ProtocolViolationException: 无法使用此动词类型发送内容主体。
既然您愿意违反GET请求的HTTP规则,我相信您唯一的选择就是坚持使用较少限制的WebClient,在这种情况下它可以正常工作。

对不起,我需要重复一遍 - 我正在与集成的 API 不符合 HTTP 规范。他们要求进行 GET 操作,并提供 Content-Type 头。 - Nagoh
好的。抱歉。我已经重新撰写了我的回复。 - Faris Zacina
谢谢,我有一种感觉那可能是唯一的选择。感谢您的帮助。 - Nagoh

3

0
我遇到了一个需要调用的 API 相同的情况,通过将内容设置为空的 StringContent,我成功地解决了这个问题:
httpRequestMessage.Content = new StringContent("", Encoding.ASCII, "application/json");

这会发送一个包含Content-TypeContent-Length (值为 0) 的标头,我调用的API可以接受。如果API拒绝带有Content-Length标头的请求,则此方法将无效。
我正在使用.NET Core 3.1。看起来OP使用的版本不支持在GET请求中设置Content属性。

0

你尝试过将头部添加到内容头部(而不是请求头部)吗?请参阅这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接