HttpClient isteği için İçerik Türü başlığını nasıl ayarlarsınız?


739

Aradığım bir API'nın gerektirdiği şekilde Content-Typebir HttpClientnesnenin başlığını ayarlamaya çalışıyorum .

Content-TypeAşağıdaki gibi ayarlamayı denedim :

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Üstbilgiyi eklememe izin veriyor, ancak eklemeye çalıştığımda Content-Typeaşağıdaki istisnayı atıyor:

Hatalı başlık adı. İstek başlıklarının HttpRequestMessage, yanıt başlıklarıyla HttpResponseMessageve içerik başlıklarıyla birlikte kullanıldığından emin olun HttpContent.

Content-TypeBir HttpClientistekte başlığı nasıl ayarlayabilirim ?


.NET Core'daki HttpWebRequest'in nasıl yaptığını takip edebilirsiniz (dahili olarak HttpClient kullanır), bkz. Github.com/dotnet/corefx/blob/master/src/System.Net.Requests/… "SendRequest" yöntemi
jiping-s

Yanıtlar:


928

İçerik türü, isteğin değil, içeriğin bir başlığıdır, bu yüzden başarısız olur. AddWithoutValidationRobert Levy tarafından önerildiği gibi çalışabilir, ancak istek içeriğini kendisi oluştururken içerik türünü de ayarlayabilirsiniz (kod snippet'inin Accept ve Content-Type başlıkları için iki yerde "application / json" eklediğini unutmayın):

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
Alternatif olarak, Response.Content.Headersçoğu zaman işe yarayacaktır.
John Gietzen

4
@AshishJain Response.Content.HeadersASP.Net Web API'siyle ilgili gördüğüm SO yanıtlarının çoğu da işe yaramadı, ancak gerekirse bunu kullanarak kolayca ayarlayabilirsiniz HttpContext.Current.Response.ContentType.
jerhewet

6
@jerhewet benim için çalışan aşağıdaki şekilde kullandım. var content = new StringContent (data, Encoding.UTF8, "application / json");
Ashish-BeJovial

22
İçerik Türü, yararlı bir HTTP mesajının özelliğidir; istekle yanıt arasında bir ilgisi yoktur.
Julian Reschke

6
İlginç. Üç parametre ile yeni bir StringContent oluşturmayı denedim ve işe yaramadı. Sonra el ile: request.Content.Headers.Remove ("Content-Type") ve sonra: request.Content.Headers.Add ("Content-Type", "application / query + json") ve çalıştı. Garip.
Bill Noel

163

Johns'u carlos çözümüne yorum yapmayanlar için ...

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

Bir pdf indirmede fark yarattı. Telefondan bir HTML indirmeye çalıştı. Uzantı dönüştürüldükten sonra dosya normal olarak kodlandı.
Matteo Defanti

Sonunda .ToString () atmak zorunda kaldım, ama evet bu bir WCF hizmeti uygulaması için çalıştı.
John Meyer

2
Sonunda deneme ve hata ile ... nesne türü "req" olduğunu anlayacağım ........ AMA bunu göstermek harika olurdu. İlginiz için teşekkürler.
granadaCoder

4
Halkın bildiği gibi, MediaTypeHeaderValue kullanmak, karakter kümesini ayarlamaya çalıştığınızda bir hata döndürür; response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml; charset=utf-8");
MBak

3
Johns, Carlo'nun çözümüne yaptığı açıklamada Response.Content.Headers dedi ancak req.Content.Headers kullanıyor musunuz? yani İstek ve Yanıt?
joedotnot

52

Küçük bir kütüphane bağımlılığı sakıncası yoksa, Flurl.Http [açıklama: Ben yazarım] bu uber-basit hale getirir. Onun PostJsonAsyncyöntemi hem içeriği seri hale ve ayar ilgilenir content-typebaşlığını ve ReceiveJsontepkisini deserializes. Eğer acceptbaşlık gereklidir kendinizi, ama Flurl da yapmak oldukça temiz bir yol sağlar bu sette gerekir:

using Flurl.Http;

var result = await "http://example.com/"
    .WithHeader("Accept", "application/json")
    .PostJsonAsync(new { ... })
    .ReceiveJson<TResult>();

Flurl, başlık altında HttpClient ve Json.NET kullanıyor ve bir PCL, bu yüzden çeşitli platformlarda çalışacak.

PM> Install-Package Flurl.Http

İçerik application / x-www-form-urlencoded ise nasıl gönderilir?
Vlado Pandžić

2
Kullanılan. <1 dakika içinde başardım ve anlaması uzun sürdü. Bu kütüphaneyi ücretsiz tuttuğunuz için teşekkür ederiz.
Najeeb

35

TryAddWithoutValidation'ı kullanmayı deneyin

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

4
çalışmıyorsa bana 'Yanlış kullanılmış başlık adı veriliyor. İstek başlıklarının HttpRequestMessage, HttpResponseMessage içeren yanıt başlıkları ve HttpContent nesneleri içeren içerik başlıkları ile kullanıldığından emin olun. '
Martin Lietz

3
HttpClient'in "çalıştığını" veya "çalıştığını" bildirenleriniz bugünlerde çok belirsiz bir nesnedir. Lütfen geldiği tam adı (boşluk) ve .dll derlemesini bildirin.
granadaCoder

Misused header nameHata dotnet çekirdek 2.2 ile onaylanır. @ Carlosfigueira'nın yanıtını stackoverflow.com/a/10679340/2084315 kullanmak zorunda kaldım .
ps2goat

tam .net işleri (4.7) için çalışır.
ZakiMa

28

Net yani o, belirli standartlara uymak için kuvvet çalışır Content-Typesadece başlık içeriğe sahip istekleri (örneğin belirtilebilir POST, PUTvb.) Bu nedenle, diğerlerinin belirttiği gibi, Content-Typeüstbilgiyi ayarlamanın tercih edilen yolu HttpContent.Headers.ContentTypeözelliktir.

Bununla birlikte, bazı API'lar ( 2016-12-19 itibariyle LiquidFiles Api gibi) Content-Typebir GETistek için üstbilginin ayarlanmasını gerektirir . .Net, bu başlığın istek üzerine kendisinin ayarlanmasına izin vermez - kullanarak TryAddWithoutValidation. Ayrıca, Contentistek için sıfır uzunluklu olsa bile bir a belirtemezsiniz . Bu almak gibi görünebilir tek yolu yansıma başvurmak oldu. Kod (başkalarının ihtiyaç duyması durumunda)

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

Düzenle:

Yorumlarda belirtildiği gibi, bu alan dll farklı sürümlerinde farklı adları vardır. In GitHub üzerinde kaynak kodu , alan şu anda adlandırılır s_invalidHeaders. Örnek, @David Thompson'un önerisi doğrultusunda bu durumu dikkate alacak şekilde değiştirildi.


1
Bu alan şimdi s_invalidHeaders olduğundan aşağıdakileri kullanmak uyumluluğu sağlar: 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
Teşekkürler teşekkürler teşekkürler! Bazen benim montaj açık asılı ve bir Microsoft API başarısız vurduğunda saçma dışarı çıkıyor .. Ben çok basit yazı gördükten sonra temizlemek mümkün. Çok kötü değil ..
Gerard ONeill

1
Bu kod açıkladığınız felaket hatalarına neden nasıl karıştı. Kullanım durumunuz ve aldığınız hatalar hakkında daha fazla bilgi verebilir misiniz?
erdomke

2
Vay. Daha da vay, Asp.net WebApi GET yöntemleri İçerik Türü açıkça belirtilmesini gerektirir = (
AlfeG

2
Holly molly, buna başvurmam gerektiğine inanamıyorum. Ne zamandan beri .NET framework devs Http başlık bölümüne ekleyebilirim ne elimi tutmak gerekir? İğrenç.
mmix

17

.NET Core hakkında bazı ek bilgiler (erdomke'nin içeriği olmayan bir istekte içerik türü sağlamak için özel bir alan ayarlama hakkındaki yazısını okuduktan sonra) ...

Kodum hata ayıklama sonra yansıma yoluyla ayarlamak için özel alan göremiyorum - bu yüzden sorunu yeniden oluşturmak çalışacağımı düşündüm.

Net 4.6 kullanarak aşağıdaki kodu denedim:

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;

Ve beklendiği gibi, içerikle ilgili toplu bir istisna alıyorum "Cannot send a content-body with this verb-type."

Ancak, .NET Core (1.1) ile aynı şeyi yaparsam - bir istisna alamadım. İsteğim sunucu uygulamam tarafından oldukça mutlu bir şekilde cevaplandı ve içerik türü alındı.

Bu konuda hoş bir sürpriz oldu ve umarım birine yardımcı olur!


1
Teşekkürler, Jay - Çekirdek kullanmıyor ve erdomke'nin cevabını kullanacak. Tüm makul yolların denendiğini bilerek teşekkür ederim :).
Gerard ONeill

1
.net 4 ({"Bu fiil türüyle bir içerik gövdesi gönderilemiyor."})
Tarek El-Mallah

3
@ TarekEl-Mallah Evet - lütfen cevabımdaki yorumları okuyun. Yazımın tüm amacı, .NET 4'te çalışmadığını, ancak .NET çekirdeğinde çalıştığını (aynı şey olmadığını) göstermekti. .NET 4'te çalışabilmek için OP'nin sorusuna erdomeke'nin cevabını görmeniz gerekecek.
Jay

16

AddWithoutValidationBunun yerine arayın Add( bu MSDN bağlantısına bakın ).

Alternatif olarak, kullandığınız API'nın gerçekten yalnızca POST veya PUT istekleri için (normal GET istekleri değil) gerektirdiğini tahmin ediyorum. Bu durumda, bir çağrı HttpClient.PostAsyncyapıp ilettiğinizde, bunu o nesnenin özelliğinde HttpContentayarlayın .HeadersHttpContent


çalışmıyorsa bana 'Yanlış kullanılmış başlık adı veriliyor. İstek başlıklarının HttpRequestMessage, HttpResponseMessage içeren yanıt başlıkları ve HttpContent nesneleri içeren içerik başlıkları ile kullanıldığından emin olun. '
Martin Lietz

3
Doğrulama yok
KansaiRobot

14

Sorun yaşayanlar için charset

Servis sağlayıcı charset kabul etmedi çok özel bir durum vardı ve izin vermek için altyapı değiştirmek için reddetti ... Ne yazık ki HttpClient otomatik olarak StringContent aracılığıyla üstbilgi ayarlamak, ve boş veya Encoding.UTF8 geçmek olursa olsun, her zaman karakter setini ayarlayacaktır ...

Bugün alt sistemi değiştirmek için uçtaydım; HttpClient'ten başka bir şeye geçiyorum, aklıma bir şey geldi ... neden "karakter setini" boşaltmak için yansıma kullanmıyorsunuz? ... Ve denemeden önce, bir yol düşündüm, "belki başlattıktan sonra değiştirebilirim" ve bu işe yaradı.

Tam olarak "application / json" üstbilgisini "; charset = utf-8" olmadan nasıl ayarlayacağınız aşağıda açıklanmıştır.

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;

Not: Aşağıdaki nulldeğer çalışmaz ve "; charset = utf-8" ifadesini ekler

return new StringContent(jsonRequest, null, "application/json");

DÜZENLE

@DesertFoxAZ ayrıca aşağıdaki kodun kullanılabileceğini ve iyi çalıştığını gösterir. (kendim test etmedim)

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

1
stringContent.Headers.ContentType = new MediaTypeHeaderValue ("application / json"); ayrıca çalışır
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"));

İhtiyacınız olan her şey.

Newtonsoft.Json kullanarak, json dizesi olarak bir içeriğe ihtiyacınız varsa.

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
Ne yaptığına dair küçük bir açıklama yapabilir misiniz?
Alejandro

2
İlk satır CS0144 ile başarısız oluyor: "Soyut sınıf veya 'HttpContent' arabiriminin bir örneği oluşturulamıyor"
Randall Flagg

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

2

Tamam, HTTPClient değil, ancak u kullanabilirsiniz, WebClient oldukça kolaydır:

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

Sen-ebilmek kullanma bu iş olacak!

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

Bunu en basit ve kolay anlaşılır şekilde buluyorum:

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

Bunu şöyle yapmanız gerekir:

    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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.