Как установить заголовок 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"));
Это все, что вам нужно.