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


739

呼び出しているAPIの要求に応じて、オブジェクトのContent-Typeヘッダーを設定しようとしHttpClientています。

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オブジェクトで使用してください 。

リクエストにContent-Typeヘッダーを設定するにはどうすればよいHttpClientですか?


あなたはそれをしない方法は、HttpWebRequestを.NETのコアで従うことができる(それはHttpClientを内部的に使用しています)を参照してくださいgithub.com/dotnet/corefx/blob/master/src/System.Net.Requests/... 「のsendRequest」方法を
jiping-sの

回答:


928

コンテンツタイプはリクエストのヘッダーではなく、コンテンツのヘッダーです。そのため、これは失敗します。AddWithoutValidationRobert Levyによって提案されたように機能する可能性がありますが、リクエストコンテンツ自体を作成するときにコンテンツタイプを設定することもできます(コードスニペットがAcceptとContent-Typeヘッダーの2つの場所に「application / json」を追加することに注意してください)。

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);
      });

32
または、Response.Content.Headersほとんどの時間で動作します。
John Gietzen

4
@AshishJain Response.Content.HeadersASP.Net Web APIに関して私が見たSOの回答のほとんども機能していませんが、HttpContext.Current.Response.ContentType必要に応じて簡単に設定できます。
jerhewet 2014年

6
@jerhewet私のために働いた次の方法で使用しました。var content = new StringContent(data、Encoding.UTF8、 "application / json");
Ashish-BeJovial 2014年

22
Content-Typeは、ペイロードを含むHTTPメッセージのプロパティです。リクエストとレスポンスは関係ありません。
Julian Reschke、

6
面白い。3つのパラメーターを使用して新しいStringContentを作成しようとしましたが、機能しませんでした。次に、手動で:request.Content.Headers.Remove( "Content-Type")、次に:request.Content.Headers.Add( "Content-Type"、 "application / query + json")と、それは機能しました。奇数。
Bill Noel、

163

ジョンズがカルロスソリューションにコメントするのを見なかった人のために...

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

PDFのダウンロードに違いが出ました。電話からHTMLをダウンロードしようとしました。拡張子を変換した後、ファイルは通常エンコードされました。
Matteo Defanti 2015

最後に.ToString()をスローする必要がありましたが、これはWCFサービスの実装で機能しました。
John Meyer

2
私は結局、試行錯誤によって「req」というオブジェクトタイプが何であるかを理解します。しかし、それを示すことは素晴らしいことです。ご検討をお願いいたします。
granadaCoder 2018

4
ご存知のように、MediaTypeHeaderValueを使用すると、文字セットを設定しようとするとエラーが返されます。response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml; charset=utf-8");
MBak

3
JohnはCarloのソリューションにコメントし、Response.Content.Headersと述べましたが、req.Content.Headersを使用していますか?つまり、リクエストとレスポンスの違いは?
joedotnot

52

小さなライブラリの依存関係を気にしない場合は、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

コンテンツがapplication / x-www-form-urlencodedの場合、どのように送信しますか?
VladoPandžić2017年

2
それを使用しました。私が理解するのに長い時間を要していたものを1分未満で達成しました。このライブラリを無料にしていただきありがとうございます。
Najeeb

35

TryAddWithoutValidationを使用してみます

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

4
機能しないと、「誤用されたヘッダー名が表示されます。リクエストヘッダーはHttpRequestMessageで、レスポンスヘッダーはHttpResponseMessageで、コンテンツヘッダーはHttpContentオブジェクトで使用してください。
Martin Lietz

3
「動作している」または「動作していない」と報告している方は、最近のHttpClientは非常にあいまいなオブジェクトです。fullname(space)とそれが由来する.dllアセンブリを報告してください。
granadaCoder 2018

Misused header nameエラーはdotnet core 2.2で確認されています。@carlosfigueiraの回答stackoverflow.com/a/10679340/2084315を使用する必要がありました。
ps2goat

それは完全な.net作品(4.7)で動作します。
ZakiMa

28

.NETは、すなわちことを、一定の基準に従うことを強制しようとするとContent-Type、ヘッダーのみコンテンツを持っているの要求(例えば上で指定することができPOSTPUTなど)。したがって、他の人が示したように、Content-Typeヘッダーを設定するための推奨される方法はHttpContent.Headers.ContentTypeプロパティを使用することです。

そうは言っても、特定のAPI(2016-12-19現在のLiquidFiles Apiなど)ではContent-TypeGETリクエストのヘッダーを設定する必要があります。.Netは、リクエスト自体にこのヘッダーを設定することを許可しませんTryAddWithoutValidation。さらに、Content長さがゼロであっても、リクエストにa を指定することはできません。私がこれを回避できるように思える唯一の方法は、反射に頼ることでした。コード(他の人がそれを必要とする場合)は

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の提案に従ってこれを説明するように変更されています。


1
このフィールドは現在s_invalidHeadersであるため、以下を使用すると互換性が保証されます。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);
David Thompson

2
ありがとう、ありがとう、ありがとう!ときどき、マウントが開いたままになり、Microsoft APIの失敗でdroolが表示されることがあります。非常に簡単な投稿を見て、クリーンアップできました。ではない、あまりにも悪い...
ジェラルド・オニール

1
このコードが、あなたが説明する壊滅的なエラーをどのように引き起こすかについて、私は混乱しています。ユースケースと受け取ったエラーの詳細を教えてください。
erdomke 2017年

2
ワオ。さらに驚いたことに、Asp.net WebApi GETメソッドでは、Content-Typeを明示的に指定する必要があります=(
AlfeG

2
ホリーモリー、私はこれに頼らなければならないなんて信じられない。.NET Framework開発者はいつHttpヘッダーセクションに追加できるものを手に入れる必要があるのですか?忌まわしい。
mmix 2018年

17

.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;

そして、予想通り、コンテンツの集計例外が発生します "Cannot send a content-body with this verb-type."

ただし、.NET Core(1.1)で同じことをした場合、例外は発生しません。私のリクエストは私のサーバーアプリケーションによって非常に喜んで答えられ、コンテンツタイプが取得されました。

嬉しい驚きでした。誰かのお役に立てば幸いです。


1
ありがとう、Jay-コアを使用せず、erdomkeの回答を使用します。すべての合理的な手段が試されたことを知って感謝します:)。
Gerard ONeill 2017

1
動作しない.net 4({"この動詞タイプのコンテンツ本体を送信できません。"})
Tarek El-Mallah '24年

3
@ TarekEl-Mallahはい-私の回答のコメントを読んでください。私の投稿の要点は、.NET 4では機能しないことを示すことでしたが、.NETコアでは機能します(同じものではありません)。あなたは.NET 4での作業にそれをハックすることができるようにOPの質問にerdomekeの回答を参照してくださいする必要があります
ジェイ・

16

AddWithoutValidation代わりにを呼び出しますAddこのMSDNリンクを参照してください)。

または、私が使用しているAPIでは、POST要求またはPUT要求(通常のGET要求ではない)に対してのみこれが必要であると思います。その場合、を呼び出しHttpClient.PostAsyncて渡したときに、そのオブジェクトのプロパティでHttpContentこれを設定HeadersHttpContentます。


機能しないと、「誤用されたヘッダー名が表示されます。リクエストヘッダーはHttpRequestMessageで、レスポンスヘッダーはHttpResponseMessageで、コンテンツヘッダーはHttpContentオブジェクトで使用してください。
Martin Lietz

3
AddWithoutValidationは存在しません
KansaiRobot

14

お困りの方へ charset

サービスプロバイダーが文字セットを受け入れない非常に特殊なケースがあり、許可するためにサブ構造を変更することを拒否しました...残念ながら、HttpClientはStringContentを介してヘッダーを自動的に設定し、nullまたはEncoding.UTF8を渡すかどうかに関係なくそれは常に文字セットを設定します...

今日、私はサブシステムを変更することを切望していました。HttpClientから他の何かに移動すると、何かが私の頭に浮かびました...リフレクションを使用して "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");

編集する

@DesertFoxAZは、次のコードも使用でき、正常に機能することを示唆しています。(自分でテストしなかった)

stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

1
stringContent.Headers.ContentType = new MediaTypeHeaderValue( "application / json"); また動作します
DesertFoxAZ

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文字列として必要な場合。

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();
    }
}

1
それが何をするのかについて少し説明してもらえますか?
アレハンドロ

2
最初の行はCS0144で失敗します:「抽象クラスまたはインターフェイス 'HttpContent'のインスタンスを作成できません」
Randall Flagg

1
その後HttpMessageHandler handler = new WebRequestHandler(); HttpResponseMessage result; using (var client = (new HttpClient(handler, true))) { result = client.PostAsync(fullUri, content).Result; }
art24war

2

OK、それは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(...);
 }

1

仕事でもこれで使える!

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

0

次のようにすると、最もシンプルで理解しやすくなります。

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

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

    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;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.