私が呼び出しているAPIの要求に応じて、HttpClient
オブジェクトのContent-Type
ヘッダーを設定しようとしています。
以下のように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");
// ...
}
それは私がAccept
ヘッダーを追加することを可能にします、しかし私がContent-Type
を追加しようとするとき、それは以下の例外を投げます:
誤ったヘッダ名リクエストヘッダが
HttpRequestMessage
、レスポンスヘッダがHttpResponseMessage
、コンテンツヘッダがHttpContent
オブジェクトで使用されていることを確認してください。
HttpClient
リクエストにContent-Type
ヘッダーを設定するにはどうすればいいですか?
コンテンツタイプはコンテンツのヘッダであり、要求のヘッダではありません。これが失敗する理由です。 Robert Levyによって提案されたAddWithoutValidation
はうまくいくかもしれませんが、リクエストコンテンツ自体を作成するときにコンテンツタイプを設定することもできます(コードスニペットが "application/json"を2箇所に追加することに注意してください)
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);
});
Johnsがカルロス解決策にコメントしていないのを見ている人のために...
req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
小さなライブラリの依存関係を気にしないのであれば、 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>();
Flurlは内部でHttpClientとJson.NETを使用していますが、これはPCLなので、さまざまなプラットフォームで動作します。
PM> Install-Package Flurl.Http
TryAddWithoutValidationを使用してみてください
var client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
.Netはあなたに特定の標準に従うことを強制しようとします、すなわち、Content-Type
ヘッダーは内容を持っている要求(例えばPOST
、PUT
など)にだけ指定されることができます。したがって、他の人が指摘したように、Content-Type
ヘッダーを設定するための好ましい方法は HttpContent.Headers.ContentType
プロパティを使用することです。
そうは言っても、特定のAPI(2016-12-19のような LiquidFiles Api など)では、GET
リクエストにContent-Type
ヘッダーを設定する必要があります。たとえTryAddWithoutValidation
を使っても.Netはリクエスト自身にこのヘッダを設定することを許可しません。さらに、リクエストにContent
を指定することはできません - たとえ長さがゼロであっても。私がこれを回避するように見えるかもしれない唯一の方法は反射に頼ることでした。コード(他の人がそれを必要とする場合)は
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の提案に従ってこれを説明するように変更されています。
AddWithoutValidation
ではなくAdd
を呼び出します( このMSDNリンクを参照 )。
代わりに、私はあなたが使っているAPIがPOSTやPUTリクエスト(通常のGETリクエストではなく)のためだけに本当に必要としていると思います。その場合は、HttpClient.PostAsync
を呼び出してHttpContent
を渡すときに、そのHeaders
オブジェクトのHttpContent
プロパティにこれを設定します。
.NET Coreに関するいくつかの追加情報(コンテンツを含まない要求でcontent-typeを提供するためのプライベートフィールドの設定に関する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;
そして、予想通り、"Cannot send a content-body with this verb-type."
という内容の例外が発生しました。
しかし、もし私が.NET Core(1.1)で同じことをするなら - 私は例外を得ない。 私の要求は私のサーバーアプリケーションによって非常に楽しく答えられ、content-typeが選択されました。
私はそれについて嬉しくて驚きました、そしてそれが誰かに役立つことを願っています!
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"));
必要なものはそれだけです。
あなたがJSON文字列としてコンテンツが必要な場合はNewtonsoft.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ではありませんが、もしuを使うことができれば、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(...);
}
charset
に問題がある人のためにサービスプロバイダーが文字セットを受け入れないという非常に特殊なケースがあり、それを許可するために下位構造を変更することを拒否します...常に文字セットを設定します...
今日、HttpClientから移動してサブシステムを変更するためにEdgeにいましたが、何かが思い浮かんだので、リフレクションを使用して「charset」を空にしてみませんか。 ...そして、試してみる前に、初期化後に変更できるものだとわかりました。 「; 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;
注:以下のnull
値は機能せず、「; charset = utf-8」を追加します
return new StringContent(jsonRequest, null, "application/json");
あなたはこれを使うことができます、それは仕事です!
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();
次の方法で最もシンプルでわかりやすいと思います。
async Task SendPostRequest()
{
HttpClient client = new HttpClient();
var requestContent = new StringContent(<content>);
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync(<url>, requestContent);
var responseString = await response.Content.ReadAsStringAsync();
}
...
SendPostRequest().Wait();
次のようにする必要があります。
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;