为HttpClient中的Get操作显式设置内容类型标头

本文关键字:类型 设置 中的 HttpClient Get 操作 | 更新日期: 2023-09-27 18:25:04

在用HttpClient执行GET时,有没有一种方法可以显式设置Content-Type标头值?

我意识到这破坏了1.1协议,但我使用的API不符合该协议,并要求我设置Content-Type头。

我试过了,但没有用。。。

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的内容类型(通过设置httpRequestMessage.Content = ...,我会得到以下错误:

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

有没有一种方法可以使用HttpClient为GET操作显式设置Content-Type

为HttpClient中的Get操作显式设置内容类型标头

根据我的发现,我得出结论,HttpClient在协议规则方面非常严格。我还通过实现DLL进行了反思,但我找不到任何表明它允许违反协议的内容。

GET请求不应该有内容类型的头,HttpClient正在强制执行该规则。

我认为当您尝试设置内容类型标头时,异常消息是自我描述的:

System.InvalidOperationException:被滥用的标头名称。请确保请求标头与HttpRequestMessage一起使用,响应标头与HttpResponseMessage一起使用以及内容标头与HttpContent对象一起使用。

此外,如果你使用设置内容主体,你会得到另一条自我描述的消息:

System.Net.ProtocolViolationException:无法发送具有此谓词类型的内容正文

由于您愿意违反GET请求的HTTP规则,我确信您唯一的选择就是使用限制较少的WebClient,它在这种情况下有效。

通过引入一个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框架的未来版本可能会通过添加AddWithoutValidation方法来支持这种类型的协议冲突:

https://msdn.microsoft.com/en-us/library/hh204926

您是否尝试过将标头添加到内容标头中(与请求标头一样)请参阅此处

我遇到了同样的情况,我需要调用一个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属性。