我正在尝试根据我调用的API的要求设置HttpClient对象的Content-Type头。
我试着把Content-Type设置如下:
1 2 3 4 5 6 7
| 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头,但是当我尝试添加Content-Type时,它抛出了以下异常:
Misused header name. Make sure request headers are used with
HttpRequestMessage, response headers with HttpResponseMessage, and
content headers with HttpContent objects.
如何在HttpClient请求中设置Content-Type头?
- 您可以按照.NET核心中的httpwebrequest的方式执行(它在内部使用httpclient),请参见github.com/dotnet/corefx/blob/master/src/system.net.requests‌&8203;/…"sendrequest"方法
内容类型是内容的头,而不是请求的头,这就是失败的原因。robert levy建议的AddWithoutValidation可能有效,但您也可以在创建请求内容本身时设置内容类型(请注意,代码片段在两个位置为accept和content-type头添加了"application/json"):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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);
}); |
- 或者,Response.Content.Headers在大多数情况下都可以工作。
- @Ashishjain我看到的大多数关于ASP.NET Web API的Response.Content.Headers的回答都没有起作用,但是如果需要,可以使用HttpContext.Current.Response.ContentType轻松设置它。
- @我用的是杰休特,这对我很有用。var content=新的stringcontent(data,encoding.utf8,"application/json");
- 内容类型是具有有效负载的HTTP消息的属性;它与请求与响应无关。
- 有趣。我尝试用这三个参数创建一个新的StringContent,但它不起作用。然后我手动:request.content.headers.remove("content-type"),然后:request.content.headers.add("content-type","application/query+json"),它就工作了。奇怪的。
- 应处置StringContent
- 什么是"relativeaddress"位?
- httpclient应该被重用(静态),并以此方式使用(不要设置基地址、默认请求头等)。
- 为什么使用MediaTypeWithQualityHeaderValue?这使我们能够设置一个MediaTypeWithQualityHeaderValue.Quality值,但是为什么我们需要它呢?
- 这很糟糕。您应该重新使用httpclient。只有当您使用httpclient处理许多不同的相关问题时,才应该使用defaultrequestheaders。httpclient应该与实例化为singleton密切相关。又名重用。
- 在哪里设置到DeleteAsync()?
- 您有什么GET方法,如何用'httpclien.getasync()设置Content-Type。
- @LP13,GET请求通常没有请求主体,所以您不需要内容类型头(因为没有内容)。
- @Carlosfigueira嗨,如果我使用HTTP GET方法,如何设置自定义请求头?任何答复都将不胜感激。
- 已确认此项工作适用于Dotnet Core 2.2
对于那些没有看到约翰对卡洛斯解决方案的评论的人…
1
| req .Content.Headers.ContentType = new MediaTypeHeaderValue ("application/octet-stream"); |
- 下载一个PDF文件有很大的不同。它试图从手机下载一个HTML。转换扩展名后,文件通常被编码。
- 最后我不得不抛出.toString(),但这对WCF服务实现是有效的。
- 我最终会找出"req"是什么类型的对象…通过尝试和错误………但这将是很好的证明。谢谢你的考虑。
- system.net.ht tp.httprequestmessage from"microsoft.netcore.app2.1.0
efetcore app 2.1system.net.ht‌&8203;tp.dll"是我找到它的地方。
- 正如人们所知道的,如果试图设置字符集,那么使用mediatypeheadervalue将返回一个错误,就像这样;response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml; charset=utf-8");。
- johns对Carlo的解决方案的评论是response.content.headers,但您使用的是req.content.headers?即请求与响应?
如果你不介意一个小的库依赖,flurl.http[公开:我是作者]使这个uber变得简单。它的PostJsonAsync方法负责对内容进行序列化和设置content-type头,ReceiveJson对响应进行反序列化。如果需要accept头文件,您需要自己设置,但是flurl也提供了一种非常干净的方法:
1 2 3 4 5 6
| using Flurl.Http;
var result = await"http://example.com/"
.WithHeader("Accept", "application/json")
.PostJsonAsync(new { ... })
.ReceiveJson<TResult >(); |
Flurl在引擎盖下使用httpclient和json.net,它是一个PCL,因此它可以在各种平台上工作。
1
| PM> Install-Package Flurl.Http |
- 如果内容是application/x-www-form-urlencoded,如何发送?
- @vlado使用PostUrlEncodedAsync。tmenier.github.io/flurl/fluent-http文件
- 看起来很有前途。谢谢。
- 用过了。在不到1分钟的时间内就完成了我花了很长时间才弄明白的事情。谢谢你让这个图书馆免费。
尝试使用TryAddWithout验证
1 2
| var client = new HttpClient ();
client .DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8"); |
- 不工作…
- 不工作会给我一个误用的标题名。确保请求头与httpRequestMessage一起使用,响应头与httpResponseMessage一起使用,内容头与httpContent对象一起使用。
- 非常适合我,谢谢!:)
- 也为我工作。!
- 对于那些报告"工作"或"不工作"的人,httpclient现在是一个非常模糊的对象。请报告它来自的全名(空格)和.dll程序集。
- 用dotnet core 2.2确认Misused header name错误。我不得不用@carlosfigueira的答案stackoverflow.com/a/10679340/2084315。
.NET试图强制您遵守某些标准,即只有在具有内容的请求(例如,POST、PUT等)上才能指定content-type头。因此,如其他人所指出的,设置content-type头的首选方法是通过HttpContent.Headers.ContentType属性。
有鉴于此,某些API(如LiquidFiles API,截至2016-12-19)需要为GET请求设置content-type头。.NET不允许根据请求本身设置此头文件--即使使用TryAddWithoutValidation。此外,您不能为请求指定一个Content——即使它的长度为零。我唯一能避开这件事的方法就是反思。代码(以防其他人需要它)是
1 2 3 4 5 6 7 8 9 10
| 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"); |
编辑:
如注释中所述,此字段在不同版本的DLL中具有不同的名称。在Github上的源代码中,该字段当前命名为s_invalidHeaders。根据@david thompson的建议,对示例进行了修改,以说明这一点。
- 不使用.NET Framework 4.0版、System.NET.HTTP 2.2.29.0版,但使用2.0.0.0.0版
- 此字段现在是"无效头",因此使用以下内容可确保兼容性:var field=typeof(system.net.http.headers.httpRequestADers).getfield("无效头",system.reflection.bindingFlags.nonpublic system.reflection.bindingFlags.static)??typeof(system.net.http.headers.httprequestaders).getfield("s_invalidheaders",system.reflection.bindingFlags.nonpublic system.reflection.bindingFlags.static);
- 为.NET核心1.1添加了与此相关的答案
- 谢谢,谢谢,谢谢!有时当我遇到一个Microsoft API失败时,我的挂载会挂起并出现下垂。在看到你的直截了当的帖子后,我才把它清理干净。还不错。
- 在.NET 4中工作
- 我应用了那个修复程序,并且发生了一个严重的错误,如果HTTP请求有问题,那么整个进一步的请求都会失败,那么整个IIS服务中的任何网络通信都会失败。我的建议是,不要使用它,而是寻找替代的解决方案。
- 我对这段代码如何导致您描述的灾难性错误感到困惑。你能提供更多关于你的用例和你收到的错误的细节吗?
- 真的。更令人惊讶的是,ASP.NET WebAPI get方法需要显式指定内容类型=(
- 霍莉·莫莉,我不敢相信我必须求助于这个。从什么时候开始,.NET框架开发需要握着我的手在我可以添加到HTTP头部分的内容中?可恶的
调用AddWithoutValidation,而不是Add(参见此msdn链接)。
或者,我猜您使用的API实际上只需要在POST或PUT请求(而不是普通的GET请求)中使用它。在这种情况下,当您调用HttpClient.PostAsync并传入一个HttpContent时,将其设置为该HttpContent对象的Headers属性。
- AddWithoutValidation引发相同的错误
- 不工作……
- 不工作会给我一个误用的标题名。确保请求头与httpRequestMessage一起使用,响应头与httpResponseMessage一起使用,内容头与httpContent对象一起使用。
- AddWithOutValidation不存在
有关.NET核心的一些额外信息(在阅读了Erdomke关于设置私有字段以在没有内容的请求上提供内容类型的文章之后)…
调试完代码后,我看不到要通过反射设置的私有字段,所以我想我会尝试重新创建这个问题。
我使用.NET 4.6尝试了以下代码:
1 2 3 4 5 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; |
而且,正如预期的那样,我得到了内容"Cannot send a content-body with this verb-type."的聚合异常。
但是,如果我对.NET核心(1.1)做同样的事情,我不会得到异常。我的请求被我的服务器应用程序很高兴地回答了,内容类型被接收了。
我对此感到很惊喜,希望它能帮助别人!
- 谢谢,杰伊——不使用core,将使用erdomke的答案。我很高兴知道所有合理的途径都已经尝试过了:)
- 确实在.NET核心中工作良好,谢谢!
- 不工作.NET 4("无法发送此动词类型的内容正文。")
- @Tarekel Mallah是的-请阅读我答案中的评论。我的文章的重点是说明它在.NET 4中不起作用,但它在.NET核心中起作用(它们不是同一回事)。你必须看到Erdomeke对OP问题的回答,才能在.NET 4中使用。
1 2 3 4
| 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字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| 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();
}
} |
- 你能解释一下它的作用吗?
- 第一行使用cs0144失败:"无法创建抽象类或接口"httpcontent"的实例。"
- 我为不完整的答案道歉:)修正。
- 然后是HttpMessageHandler handler = new WebRequestHandler(); HttpResponseMessage result; using (var client = (new HttpClient(handler, true))) { result = client.PostAsync(fullUri, content).Result; }。
好吧,这不是httpclient,但是如果你能使用它,webclient就很容易了:
1 2 3 4 5 6
| 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(...);
} |