it-swarm.com.de

Wie legen Sie den Content-Type-Header für eine HttpClient-Anforderung fest?

Ich versuche, den Content-Type -Header eines HttpClient -Objekts gemäß den Anforderungen einer von mir aufgerufenen API festzulegen.

Ich habe versucht, den Content-Type wie folgt einzustellen:

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");
    // ...
}

Ich kann den Header Accept hinzufügen, aber wenn ich versuche, Content-Type hinzuzufügen, wird die folgende Ausnahme ausgelöst:

Name des falsch verwendeten Headers. Stellen Sie sicher, dass Anforderungsheader mit HttpRequestMessage, Antwortheader mit HttpResponseMessage und Inhaltsheader mit HttpContent Objekten verwendet werden.

Wie kann ich den Content-Type -Header in einer HttpClient -Anforderung festlegen?

633
mynameiscoffey

Der Inhaltstyp ist eine Kopfzeile des Inhalts und nicht der Anforderung, weshalb dies fehlschlägt. AddWithoutValidation, wie von Robert Levy vorgeschlagen, funktioniert möglicherweise, aber Sie können den Inhaltstyp auch festlegen, wenn Sie den Anforderungsinhalt selbst erstellen (beachten Sie, dass das Code-Snippet "application/json" an zwei Stellen für die Überschriften "Accept" und "Content-Type" hinzufügt ):

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

Für diejenigen, die Johns Kommentar zur Carlos-Lösung nicht gesehen haben ...

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

Wenn Ihnen eine kleine Bibliotheksabhängigkeit nichts ausmacht, macht Flurl.Http [Offenlegung: Ich bin der Autor] dies sehr einfach. Die PostJsonAsync -Methode sorgt sowohl für die Serialisierung des Inhalts als auch für das Setzen des content-type -Headers, und ReceiveJson deserialisiert die Antwort. Wenn der accept -Header benötigt wird, müssen Sie dies selbst festlegen, aber Flurl bietet auch eine ziemlich saubere Möglichkeit, dies zu tun:

using Flurl.Http;

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

Flurl verwendet HttpClient und Json.NET unter der Haube, und es ist eine PCL, so dass es auf einer Vielzahl von Plattformen funktioniert.

PM> Install-Package Flurl.Http
49
Todd Menier

versuchen Sie TryAddWithoutValidation zu verwenden

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

.Net versucht, Sie zur Einhaltung bestimmter Standards zu zwingen, nämlich, dass der Header _Content-Type_ nur für Anforderungen angegeben werden kann, die Inhalt haben (z. B. POST, PUT usw.). Wie bereits von anderen angegeben, erfolgt das Festlegen des Headers _Content-Type_ daher bevorzugt über die Eigenschaft HttpContent.Headers.ContentType .

Vor diesem Hintergrund muss für bestimmte APIs (wie die LiquidFiles Api , Stand 19.12.2016) der _Content-Type_ -Header für eine GET -Anforderung festgelegt werden. .Net erlaubt es nicht, diesen Header für die Anfrage selbst festzulegen - selbst wenn TryAddWithoutValidation verwendet wird. Darüber hinaus können Sie für die Anforderung kein Content angeben, selbst wenn es eine Länge von Null hat. Der einzige Weg, wie ich das umgehen konnte, bestand darin, auf Reflexion zurückzugreifen. Der Code (falls er von anderen benötigt wird) ist

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

Bearbeiten:

Wie in den Kommentaren erwähnt, hat dieses Feld in verschiedenen Versionen der DLL unterschiedliche Namen. Im Quellcode auf GitHub heißt das Feld derzeit _s_invalidHeaders_. Das Beispiel wurde geändert, um dies auf Vorschlag von @David Thompson zu berücksichtigen.

24
erdomke

Einige zusätzliche Informationen zu .NET Core (nach dem Lesen des Postings von erdomke zum Festlegen eines privaten Felds, um den Inhaltstyp für eine Anfrage ohne Inhalt bereitzustellen) ...

Nach dem Debuggen meines Codes kann ich das private Feld, das über Reflection festgelegt werden soll, nicht sehen. Daher dachte ich, ich würde versuchen, das Problem erneut zu erstellen.

Ich habe den folgenden Code mit .Net 4.6 ausprobiert:

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;

Und wie erwartet erhalte ich eine aggregierte Ausnahme mit dem Inhalt "Cannot send a content-body with this verb-type."

Wenn ich jedoch das Gleiche mit .NET Core (1.1) mache - Ich bekomme keine Ausnahme. Meine Anfrage wurde von meiner Serveranwendung sehr zufrieden beantwortet und der Inhaltstyp wurde abgeholt .

Das hat mich positiv überrascht und ich hoffe es hilft jemandem!

16
Jay

Rufen Sie AddWithoutValidation anstelle von Add auf (siehe dieser MSDN-Link ).

Alternativ schätze ich, dass die von Ihnen verwendete API dies nur für POST - oder PUT-Anforderungen (keine normalen GET-Anforderungen) benötigt. Wenn Sie in diesem Fall HttpClient.PostAsync aufrufen und ein HttpContent übergeben, legen Sie dies für die Headers -Eigenschaft dieses HttpContent -Objekts fest.

15
Robert Levy
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"));

Es ist alles was Sie brauchen.

Mit der Verwendung von Newtonsoft.Json, wenn Sie einen Inhalt als JSON-Zeichenfolge benötigen.

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

Ok, es ist nicht HTTPClient, aber wenn Sie es verwenden können, ist WebClient ganz einfach:

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

Für diejenigen, die Probleme mit charset haben

Ich hatte einen ganz besonderen Fall, in dem der Dienstanbieter Zeichensatz nicht akzeptierte und sich weigerte, die Unterstruktur zu ändern, um dies zuzulassen. es wird immer den Zeichensatz setzen ...

Heute war ich am Rande, um das Subsystem zu ändern, als ich von HttpClient auf etwas gestoßen bin. Warum sollte ich nicht die Reflektion verwenden, um den "Zeichensatz" zu leeren? ... und bevor ich es überhaupt probiere, habe ich festgestellt, dass ich es nach der Initialisierung ändern kann. Hier erfahren Sie, wie Sie den genauen "application/json" -Header ohne "; charset = utf-8" festlegen können.

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;

Hinweis: Der folgende null -Wert funktioniert nicht und hängt "; charset = utf-8" an

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

Sie können dies verwenden, es wird funktionieren!

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

Ich finde es am einfachsten und verständlichsten auf folgende Weise:

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

Du musst es so machen:

    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