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

时间:2014-09-29 22:04:00

标签: c# .net dotnet-httpclient

在使用Content-Type执行GET时,我是否可以明确设置HttpClient标头值?

我意识到这会破坏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)
}

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

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

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

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

5 个答案:

答案 0 :(得分:6)

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

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

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

  

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

此外,如果您使用设置内容正文,则会获得一条自我描述性消息:

  

System.Net.ProtocolViolationException:无法使用此动词类型发送内容正文。

由于您愿意违反GET请求的HTTP规则,因此我非常确定您唯一的选择是坚持使用限制较少的WebClient,它适用于该场景。

答案 1 :(得分:5)

可能 - 而且非常脏 - 用一些反射覆盖库行为,并引入一个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)
            .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;
    }
}

答案 2 :(得分:1)

虽然现在没有任何帮助,但看起来.NET框架的未来版本可能会通过添加AddWithoutValidation方法来支持这种类型的协议违规:

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

答案 3 :(得分:0)

您是否尝试过向内容标题添加标题(与请求标头一起使用) 见here

答案 4 :(得分:0)

我遇到了需要调用的API的情况,我可以通过将内容设置为空的StringContent来解决此问题:

httpRequestMessage.Content = new StringContent("", Encoding.ASCII, "application/json");

这同时发送一个Content-Type和一个Content-Length头(值为0),我正在调用的API可以使用。如果API拒绝带有Content-Length标头的请求,则此方法将无效。

我正在使用.NET Core 3.1。看来OP使用的版本不支持在GET请求上设置Content属性。