Question Comment définissez-vous l'en-tête Content-Type pour une requête HttpClient?


J'essaie de mettre le Content-Type en-tête d'un HttpClient objet comme requis par une API que j'appelle.

J'ai essayé de régler le Content-Type comme ci-dessous:

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

Cela me permet d'ajouter le Accept en-tête mais quand j'essaie d'ajouter Content-Type il jette l'exception suivante:

Nom d'en-tête mal utilisé. Assurez-vous que les en-têtes de demande sont utilisés avec    HttpRequestMessage, en-têtes de réponse avec HttpResponseMessage, et   en-têtes de contenu avec HttpContent objets.

Comment puis-je définir le Content-Type en-tête dans un HttpClient demande?


466
2018-05-21 03:29


origine


Réponses:


Le type de contenu est un en-tête du contenu et non de la demande, ce qui explique son échec. AddWithoutValidation comme suggéré par Robert Levy peut fonctionner, mais vous pouvez également définir le type de contenu lors de la création du contenu de la requête lui-même (notez que l'extrait de code ajoute "application / json" à deux endroits pour les en-têtes Accept et Content-Type):

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

580
2018-05-21 03:54



Pour ceux qui n'ont pas vu Johns commenter à la solution de Carlos ...

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

103
2018-06-06 10:15



Si cela ne vous dérange pas une petite dépendance de la bibliothèque, Flurl.Http [divulgation: je suis l'auteur] rend cela ultra-simple. Ses PostJsonAsync méthode prend soin à la fois la sérialisation du contenu et la définition de la content-type en-tête, et ReceiveJson désérialise la réponse. Si la accept Vous devez définir vous-même l'en-tête, mais Flurl fournit également un moyen assez simple de le faire:

using Flurl.Http;

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

Flurl utilise HttpClient et Json.NET sous le capot, et c'est un PCL qui fonctionnera sur une variété de plates-formes.

PM> Install-Package Flurl.Http

37
2018-06-22 15:19



essayez d'utiliser TryAddWithoutValidation 

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

25
2017-11-19 22:48



Appel AddWithoutValidation au lieu de Add (voir ce lien MSDN).

Sinon, je suppose que l'API que vous utilisez ne l'exige que pour les requêtes POST ou PUT (et non pour les requêtes GET ordinaires). Dans ce cas, lorsque vous appelez HttpClient.PostAsync et passer dans un HttpContent, mettez ceci sur le Headers propriété de HttpContent objet.


15
2018-05-21 03:32



.Net essaie de vous forcer à respecter certaines normes, à savoir que le Content-Type L'en-tête ne peut être spécifié que pour les requêtes qui ont du contenu (par ex. POST, PUT, etc.). Par conséquent, comme d'autres l'ont indiqué, la manière préférée de définir Content-Type l'en-tête est à travers le HttpContent.Headers.ContentType propriété.

Cela dit, certaines API (telles que la LiquidFiles Api, à partir du 19/12/2016) nécessite de régler le Content-Type en-tête pour un GET demande. .Net ne permettra pas de définir cet en-tête sur la demande elle-même - même en utilisant TryAddWithoutValidation. De plus, vous ne pouvez pas spécifier de Content pour la demande - même si elle est de longueur nulle. Le seul moyen de contourner ce problème était de recourir à la réflexion. Le code (au cas où une autre en aurait besoin) est

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

Modifier:

Comme indiqué dans les commentaires, ce champ a des noms différents dans différentes versions de la DLL. dans le code source sur GitHub, le champ est actuellement nommé s_invalidHeaders. L'exemple a été modifié pour tenir compte de ceci par la suggestion de @David Thompson.


13
2017-12-19 21:32



Quelques informations supplémentaires sur .NET Core (après avoir lu le post de erdomke sur la définition d'un champ privé pour fournir le type de contenu sur une requête qui n'a pas de contenu) ...

Après avoir débogué mon code, je ne peux pas voir le champ privé à définir par réflexion - alors j'ai pensé que j'essaierais de recréer le problème.

J'ai essayé le code suivant en utilisant .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;

Et, comme prévu, je reçois une exception globale avec le contenu "Cannot send a content-body with this verb-type." 

Cependant, si je fais la même chose avec .NET Core (1.1) - Je ne reçois pas d'exception. Ma demande de serveur a été très satisfaisante, et le type de contenu a été choisi.

J'ai été agréablement surpris à ce sujet, et j'espère que ça aide quelqu'un!


11
2018-06-12 08:48



var content = new HttpContent();
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"));

C'est tout ce dont vous avez besoin.


0
2018-05-28 13:56



Ok, ce n'est pas HTTPClient mais si vous pouvez l'utiliser, WebClient est assez facile:

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

0
2017-07-09 20:21