Как установить заголовок Content-Type для запроса HttpClient?

Я пытаюсь установить Content-Type заголовок HttpClient объект, как требуется API, который я вызываю.

Я попытался установить 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 запрос?

9 ответов


тип содержимого является заголовком содержимого, а не запроса, поэтому это не удается. AddWithoutValidation как предложил Роберт Леви, может работать, но вы также можете установить тип контента при создании самого контента запроса (обратите внимание, что фрагмент кода добавляет "application / json" в двух местах-для заголовков Accept и 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);
      });

для тех, кто не видел, как Джонс комментирует решение Карлоса ...

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

если вы не против небольшой зависимости библиотеки,Flurl.Протокол HTTP [раскрытие: я-автор делает это супер-простой. Его PostJsonAsync метод заботится как о сериализации содержимого, так и о настройке и 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

попробуйте использовать TryAddWithoutValidation

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

вызов AddWithoutValidation вместо Add (см. эта ссылка MSDN).

кроме того, я предполагаю, что API, который вы используете, действительно требует этого только для запросов POST или PUT (не обычные запросы GET). В том случае, когда вы звоните HttpClient.PostAsync и передать ему HttpContent, расположен на Headers свойства HttpContent "объект".


.Net пытается заставить вас подчиняться определенным стандартам, а именно, что Content-Type заголовок может быть указан только в запросах с содержимым (например,POST, PUT, etc.). Поэтому, как указывали другие, предпочтительный способ установить Content-Type заголовок через HttpContent.Headers.ContentType собственность.

С этим сказал, Некоторые APIs (такие как LiquidFiles Api, по состоянию на 2016-12-19) требует установки на GET запрос. .Чистый не позволит установить этот заголовок в самом запросе - даже используя TryAddWithoutValidation. Кроме того, вы не можете указать 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");

Edit:

как отмечено в комментариях, это поле имеет разные имена в разных версиях dll. В исходный код На GitHub поле . Пример был изменен для учета этого по предложению @David Thompson.


дополнительная информация о .NET Core (после прочтения сообщения эрдомке о настройке частного поля для предоставления типа контента по запросу, у которого нет контента)...

после отладки моего кода я не вижу частного поля для установки через отражение - поэтому я подумал, что попытаюсь воссоздать проблему.

я попробовал следующий код с помощью .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) - Я не получаю исключение. на мой запрос с радостью ответило мое серверное приложение, и тип контента был подобран.

Я был приятно удивлен этим, и я надеюсь, что это поможет кому-то!


хорошо, это не 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(...);
 }

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

Это все, что вам нужно.