为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在协议规则方面非常严格。我还通过实现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-Type
和Content-Length
报头(值为0
),我正在调用的API可以使用它们。如果API拒绝具有Content-Length
头的请求,那么这将不起作用。
我使用的是.NET Core 3.1。OP使用的版本似乎不支持在GET请求上设置Content
属性。