web-dev-qa-db-ja.com

HttpClientリクエストにContent-Typeヘッダーをどのように設定しますか?

私が呼び出している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ヘッダーを設定するにはどうすればいいですか?

588
mynameiscoffey

コンテンツタイプはコンテンツのヘッダであり、要求のヘッダではありません。これが失敗する理由です。 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);
      });
741
carlosfigueira

Johnsがカルロス解決策にコメントしていないのを見ている人のために...

req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
124
archgl

小さなライブラリの依存関係を気にしないのであれば、 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
47
Todd Menier

TryAddWithoutValidationを使用してみてください

  var client = new HttpClient();
  client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
29
SharpCoder

.Netはあなたに特定の標準に従うことを強制しようとします、すなわち、Content-Typeヘッダーは内容を持っている要求(例えばPOSTPUTなど)にだけ指定されることができます。したがって、他の人が指摘したように、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の提案に従ってこれを説明するように変更されています。

21
erdomke

AddWithoutValidationではなくAddを呼び出します( このMSDNリンクを参照 )。

代わりに、私はあなたが使っているAPIがPOSTやPUTリクエスト(通常のGETリクエストではなく)のためだけに本当に必要としていると思います。その場合は、HttpClient.PostAsyncを呼び出してHttpContentを渡すときに、そのHeadersオブジェクトのHttpContentプロパティにこれを設定します。

15
Robert Levy

.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が選択されました。

私はそれについて嬉しくて驚きました、そしてそれが誰かに役立つことを願っています!

14
Jay
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();
    }
}
3
art24war

さて、それは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(...);
 }
2
Ziba Leah

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");
1
deadManN

あなたはこれを使うことができます、それは仕事です!

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();
1
Kumaran

次の方法で最もシンプルでわかりやすいと思います。

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();
0
getThingsDone

次のようにする必要があります。

    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;
0
user890332