我试图设置一个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头,但当我尝试添加Content-Type时,它会抛出以下异常:
误用头名称。确保请求头与一起使用
HttpRequestMessage,带有HttpResponseMessage的响应头,以及
内容头与HttpContent对象。
如何在HttpClient请求中设置内容类型报头?
内容类型是内容的头,而不是请求的头,这就是失败的原因。Robert Levy建议的AddWithoutValidation可以工作,但是你也可以在创建请求内容本身时设置内容类型(注意,代码片段在两个地方添加了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);
});
如果你不介意一个小的库依赖,Flurl。Http[披露:我是作者]使这个超级简单。它的PostJsonAsync方法负责序列化内容和设置内容类型报头,而ReceiveJson则反序列化响应。如果accept头是必需的,你需要自己设置,但Flurl提供了一个非常干净的方式来做到这一点:
using Flurl.Http;
var result = await "http://example.com/"
.WithHeader("Accept", "application/json")
.PostJsonAsync(new { ... })
.ReceiveJson<TResult>();
Flurl使用HttpClient和Json。它是一个PCL,所以它可以在各种平台上工作。
PM> Install-Package Flurl.Http
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();
}
}
对于我的场景,第三方API正在创建HttpRequestMessage,因此我无法使用投票最多的答案来解决这个问题。我不喜欢干扰反射的想法所以其他答案也不成立。
相反,我从AndroidMessageHandler扩展,并使用这个新类作为HttpClient的参数。AndroidMessageHandler包含SendAsync方法,可以在HttpRequestMessage对象发送之前重写该方法。如果您没有访问Android Xamarin库的权限,您可以使用HttpMessageHandler来解决一些问题。
public class XamarinHttpMessageHandler : global::Xamarin.Android.Net.AndroidMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Here I make check that I'm only modifying a specific request
// and not all of them.
if (request.RequestUri != null && request.RequestUri.AbsolutePath.EndsWith("download") && request.Content != null)
{
request.Content.Headers.Add("Content-Type", "text/plain");
}
return base.SendAsync(request, cancellationToken);
}
}
然后使用:
var client = new HttpClient(new XamarinHttpMessageHandler());