myn*_*fey 677 c# asp.net api rest http
我正在尝试根据我调用的API 设置对象的Content-Type
标头HttpClient
.
我尝试过Content-Type
如下设置:
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");
// ...
}
Run Code Online (Sandbox Code Playgroud)
它允许我添加Accept
标题但是当我尝试添加Content-Type
它时抛出以下异常:
未使用的标题名称.确保请求标头与对象
HttpRequestMessage
一起使用 ,响应标头HttpResponseMessage
和带有HttpContent
对象的内容标头.
如何Content-Type
在HttpClient
请求中设置标头?
car*_*ira 844
内容类型是内容的标题,而不是请求的标题,这就是失败的原因.AddWithoutValidation
正如Robert Levy所建议的那样,你也可以在创建请求内容时设置内容类型(请注意,代码片段在两个地方添加了"application/json" - 对于Accept和Content-Type标头):
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://example.com/");
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress");
request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}",
Encoding.UTF8,
"application/json");//CONTENT-TYPE header
client.SendAsync(request)
.ContinueWith(responseTask =>
{
Console.WriteLine("Response: {0}", responseTask.Result);
});
Run Code Online (Sandbox Code Playgroud)
arc*_*hgl 150
对于那些没有看到约翰斯评论卡洛斯解决方案的人......
req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
Run Code Online (Sandbox Code Playgroud)
Tod*_*ier 49
如果你不介意一个小的库依赖,Flurl.Http [披露:我是作者]使这个超级简单.它的PostJsonAsync
方法既负责序列化内容又设置content-type
标题,并ReceiveJson
反序列化响应.如果accept
标题是必需的,你需要自己设置,但Flurl也提供了一种非常干净的方法:
using Flurl.Http;
var result = await "http://example.com/"
.WithHeader("Accept", "application/json")
.PostJsonAsync(new { ... })
.ReceiveJson<TResult>();
Run Code Online (Sandbox Code Playgroud)
Flurl使用HttpClient和Json.NET,它是一个PCL,因此它可以在各种平台上运行.
PM> Install-Package Flurl.Http
Run Code Online (Sandbox Code Playgroud)
Sha*_*der 28
尝试使用TryAddWithoutValidation
var client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
Run Code Online (Sandbox Code Playgroud)
erd*_*mke 25
.NET试图迫使你遵守一定的标准,即在Content-Type
头只能在有内容(例如,请求指定POST
,PUT
等等).因此,正如其他人所指出的那样,设置Content-Type
标题的首选方法是通过HttpContent.Headers.ContentType
属性.
话虽如此,某些API(例如LiquidFiles Api,截至2016-12-19)需要Content-Type
为GET
请求设置标头..Net不允许在请求本身上设置此标头 - 即使使用TryAddWithoutValidation
.此外,您不能Content
为请求指定a - 即使它是零长度.我似乎唯一可以解决这个问题的方法就是求助于反思.代码(如果其他人需要它)是
var field = typeof(System.Net.Http.Headers.HttpRequestHeaders)
.GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
?? typeof(System.Net.Http.Headers.HttpRequestHeaders)
.GetField("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
if (field != null)
{
var invalidFields = (HashSet<string>)field.GetValue(null);
invalidFields.Remove("Content-Type");
}
_client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml");
Run Code Online (Sandbox Code Playgroud)
编辑:
如评论中所述,该字段在dll的不同版本中具有不同的名称.在GitHub的源代码中,该字段当前已命名s_invalidHeaders
.根据@David Thompson的建议,该示例已经过修改以解释此问题.
Rol*_*and 21
诀窍是您可以设置各种标头,例如:
HttpRequestMessage request = new HttpRequestMessage();
request.Headers.Add("Accept-Language", "en"); //works OK
Run Code Online (Sandbox Code Playgroud)
但没有任何标题。例如:
request.Headers.Add("Content-Type", "application/json");//wrong
Run Code Online (Sandbox Code Playgroud)
将引发运行时异常Misused header name
。这似乎可行:
request.Headers.Add(
HttpRequestHeader.ContentType.ToString(), //useless
"application/json"
);
Run Code Online (Sandbox Code Playgroud)
但这给出了一个名为 的无用标头ContentType
,没有连字符。标头名称不区分大小写,但对连字符非常敏感。
解决方案是在将body添加到http请求的Content部分时声明body的编码和类型:
string Body = "...";
request.Content = new StringContent(Body, Encoding.UTF8, "application/json");
Run Code Online (Sandbox Code Playgroud)
只有这样,适用的 http 标头才会自动添加到请求中,例如:
Content-Type: application/json; charset=utf-8
Run Code Online (Sandbox Code Playgroud)
在没有代理服务器的机器上使用 Fiddler 很难发现这一点。Visual Studio 曾经有一个网络工具,您可以在其中检查所有标头,但仅限于 2015 版本,而不是较新版本 2017 或 2022。如果您使用调试器检查 ,您将request.Headers
找不到StringContent()
.
Jay*_*Jay 16
关于.NET Core的一些额外信息(在阅读erdomke关于设置私有字段以在没有内容的请求上提供内容类型的帖子之后)...
在调试我的代码之后,我看不到要通过反射设置的私有字段 - 所以我想我会尝试重新创建问题.
我使用.Net 4.6尝试了以下代码:
HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, @"myUrl");
httpRequest.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
Task<HttpResponseMessage> response = client.SendAsync(httpRequest); //I know I should have used async/await here!
var result = response.Result;
Run Code Online (Sandbox Code Playgroud)
并且,正如预期的那样,我得到了内容的聚合异常 "Cannot send a content-body with this verb-type."
但是,如果我使用.NET Core(1.1)做同样的事情 - 我没有例外.我的服务器应用程序很满意地回答了我的请求,并且拾取了内容类型.
我对此感到惊喜,我希望它对某人有所帮助!
小智 7
你可以用这个,它会起作用的!
HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Get,"URL");
msg.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.SendAsync(msg);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
Run Code Online (Sandbox Code Playgroud)
charset
我有一个非常特殊的情况,服务提供者不接受字符集,并且他们拒绝更改子结构以允许它...不幸的是,HttpClient通过StringContent自动设置了标头,无论您传递null还是Encoding.UTF8,它将始终设置字符集...
今天,我处于改变子系统的边缘。从HttpClient迁移到其他事物,我想到了什么……,为什么不使用反射来清空“字符集”?...并且在我什至尝试之前,我想到了一种方法,“也许我可以在初始化后进行更改”,并且这种方法行得通。
这是在不带“; charset = utf-8”的情况下设置确切的“ application / json”标头的方法。
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;
Run Code Online (Sandbox Code Playgroud)
注意:null
后面的值不起作用,并附加“; charset = utf-8”
return new StringContent(jsonRequest, null, "application/json");
Run Code Online (Sandbox Code Playgroud)
对于任何需要 Get 等内容类型标头的人,虽然在较旧的 .NET 版本中,可以使用/sf/answers/2886194741/上的 @erdomke 的答案,但不幸的是,这不再适用于较新的 .NET Core 版本。
以下代码已经过测试,可以与 .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);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
700892 次 |
最近记录: |