C# 如何设置HttpClient请求的内容类型标头?
我正在尝试设置C# 如何设置HttpClient请求的内容类型标头?,c#,asp.net,rest,content-type,dotnet-httpclient,C#,Asp.net,Rest,Content Type,Dotnet Httpclient,我正在尝试设置HttpClient对象的Content-Type头,以满足我调用的API的要求 我尝试设置内容类型,如下所示: using (var httpClient = new HttpClient()) { httpClient.BaseAddress = new Uri("http://example.com/"); httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); httpC
HttpClient
对象的Content-Type
头,以满足我调用的API的要求
我尝试设置内容类型
,如下所示:
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");
// ...
}
它允许我添加Accept
标题,但当我尝试添加内容类型时,它会引发以下异常:
误用的标题名。确保请求头与
HttpRequestMessage
,带有HttpResponseMessage
的响应头,以及
包含HttpContent
对象的内容标题
如何在HttpClient
请求中设置Content-Type
标题?调用AddWithoutValidation
,而不是Add
(请参阅)
或者,我猜您正在使用的API实际上只对POST或PUT请求(而不是普通的GET请求)要求这样做。在这种情况下,当您调用HttpClient.PostAsync
并传入HttpContent
时,在该HttpContent
对象的Headers
属性上设置该属性。内容类型是内容的头,而不是请求的头,这就是失败的原因。可以工作,但您也可以在创建请求内容本身时设置内容类型(请注意,代码段在两个位置添加了application/json
,用于Accept和content-type头):
对于那些没有看到约翰评论卡洛斯解决方案的人
req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
如果你不介意一个小的库依赖,[披露:我是作者]使优步变得简单。它的PostJsonAsync
方法负责序列化内容和设置content-type
标题,并且ReceiveJson
反序列化响应。如果需要accept
标题,您需要自己设置,但Flurl也提供了一种非常简洁的方法:
using Flurl.Http;
var result = await "http://example.com/"
.WithHeader("Accept", "application/json")
.PostJsonAsync(new { ... })
.ReceiveJson<TResult>();
尝试在没有验证的情况下使用tryadd
var client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
.Net试图强制您遵守某些标准,即内容类型
标题只能在包含内容的请求上指定(例如POST
,PUT
等)。因此,正如其他人所指出的,设置内容类型
标题的首选方法是通过属性
尽管如此,某些API(如,截至2016年12月19日)需要为GET
请求设置内容类型
标题。Net将不允许在请求本身上设置此标头--即使使用tryadd而不进行验证
。此外,您不能为请求指定内容
——即使它的长度为零。我似乎唯一能绕过这个问题的方法就是诉诸反思。代码(以防其他人需要)是
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);
如果(字段!=null)
{
var invalidFields=(HashSet)field.GetValue(null);
invalidFields.Remove(“内容类型”);
}
_client.DefaultRequestHeaders.TryAddWithoutValidation(“内容类型”、“文本/xml”);
编辑:
如注释中所述,此字段在dll的不同版本中具有不同的名称。在中,该字段当前命名为s\u invalidHeaders
。根据@David Thompson的建议,对示例进行了修改以说明这一点。关于.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;
HttpRequestMessage httpRequest=newhttprequestmessage(HttpMethod.Get,@“myUrl”);
httpRequest.Content=newstringcontent(string.Empty,Encoding.UTF8,“application/json”);
HttpClient=新的HttpClient();
任务响应=client.sendaync(httpRequest)//我知道我应该在这里使用async/Wait!
var result=response.result;
而且,正如预期的那样,我得到了一个聚合异常,内容为“无法发送具有此动词类型的内容正文。”
但是,如果我对.NET Core(1.1)做同样的事情,我不会得到例外。我的服务器应用程序很高兴地回答了我的请求,并且选择了内容类型
我对此感到惊喜,我希望这对别人有帮助
var content = new JsonContent();
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("charset", "utf-8"));
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("IEEE754Compatible", "true"));
这就是你所需要的
使用Newtonsoft.Json,如果您需要一个内容作为Json字符串
public class JsonContent : HttpContent
{
private readonly MemoryStream _stream = new MemoryStream();
~JsonContent()
{
_stream.Dispose();
}
public JsonContent(object value)
{
Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var contexStream = new MemoryStream())
using (var jw = new JsonTextWriter(new StreamWriter(contexStream)) { Formatting = Formatting.Indented })
{
var serializer = new JsonSerializer();
serializer.Serialize(jw, value);
jw.Flush();
contexStream.Position = 0;
contexStream.WriteTo(_stream);
}
_stream.Position = 0;
}
private JsonContent(string content)
{
Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var contexStream = new MemoryStream())
using (var sw = new StreamWriter(contexStream))
{
sw.Write(content);
sw.Flush();
contexStream.Position = 0;
contexStream.WriteTo(_stream);
}
_stream.Position = 0;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return _stream.CopyToAsync(stream);
}
protected override bool TryComputeLength(out long length)
{
length = _stream.Length;
return true;
}
public static HttpContent FromFile(string filepath)
{
var content = File.ReadAllText(filepath);
return new JsonContent(content);
}
public string ToJsonString()
{
return Encoding.ASCII.GetString(_stream.GetBuffer(), 0, _stream.GetBuffer().Length).Trim();
}
}
好的,它不是HTTPClient,但如果您可以使用它,WebClient非常简单:
using (var client = new System.Net.WebClient())
{
client.Headers.Add("Accept", "application/json");
client.Headers.Add("Content-Type", "application/json; charset=utf-8");
client.DownloadString(...);
}
我发现以下方式最简单、最容易理解:
异步任务SendPostRequest()
{
HttpClient=新的HttpClient();
var requestContent=new StringContent();
requestContent.Headers.ContentType=新的MediaTypeHeaderValue(“应用程序/json”);
var response=wait client.PostAsync(,requestContent);
var responseString=await response.Content.ReadAsStringAsync();
}
...
SendPostRequest().Wait();
你可以用这个,它会有用的
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();
您需要这样做:
HttpContent httpContent = new StringContent(@"{ the json string }");
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage message = client.PostAsync(@"{url}", httpContent).Result;
对于那些遇到charset
我遇到了一个非常特殊的情况,服务提供商不接受charset,他们拒绝更改子结构以允许它。。。
不幸的是,HttpClient是通过StringContent自动设置标题的,无论您传递null还是Encoding.UTF8,它都会设置字符集
今天我在改变子系统的边缘;从HttpClient转移到其他任何东西,这是某种东西产生的结果
using (var client = new System.Net.WebClient())
{
client.Headers.Add("Accept", "application/json");
client.Headers.Add("Content-Type", "application/json; charset=utf-8");
client.DownloadString(...);
}
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();
HttpContent httpContent = new StringContent(@"{ the json string }");
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage message = client.PostAsync(@"{url}", httpContent).Result;
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;
return new StringContent(jsonRequest, null, "application/json");
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
services.AddSingleton<WebRequestXXX>()
.AddHttpClient<WebRequestXXX>("ClientX", config =>
{
config.BaseAddress = new System.Uri("https://jsonplaceholder.typicode.com");
config.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
config.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
});
public class WebRequestXXXX
{
private readonly IHttpClientFactory _httpClientFactory;
public WebRequestXXXX(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public List<Posts> GetAllPosts()
{
using (var _client = _httpClientFactory.CreateClient("ClientX"))
{
var response = _client.GetAsync("/posts").Result;
if (response.IsSuccessStatusCode)
{
var itemString = response.Content.ReadAsStringAsync().Result;
var itemJson = System.Text.Json.JsonSerializer.Deserialize<List<Posts>>(itemString,
new System.Text.Json.JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return itemJson;
}
else
{
return new List<Posts>();
}
}
}
}
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);
}
private async Task<string> GetAccessTokenAsync()
{
var client = new RestClient(_baseURL);
var request = new RestRequest("auth/v1/login", Method.POST, DataFormat.Json);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("x-api-key", _apiKey);
request.AddHeader("Accept-Language", "br");
request.AddHeader("x-client-tenant", "1");
...
}