Явно задайте заголовки Content-Type для получения работы в HttpClient
Есть ли способ, в котором я могу явно установить значения заголовка Content-Type
при выполнении GET
с HttpClient
?
Я понимаю этот протокол breaks 1.1, но я работаю с API, который не соответствует ему, и НЕОБХОДИМО установить набор заголовков Content-Type
.
Я пробовал это безрезультатно...
using (var httpClient = new HttpClient())
{
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://example.com");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded+v1.3");
await httpClient.SendAsync(httpRequestMessage)
}
Я проверил DefaultRequestHeaders
после добавления TryAddWithoutValidation
и, похоже, не устанавливает значение Content-Type
.
Если я попытаюсь установить Content-Type httpRequestMessage (установив httpRequestMessage.Content = ...
, я получаю следующую ошибку:
Cannot send a content-body with this verb-type.
Есть ли способ, который я могу явно установить Content-Type
для операции GET
с помощью HttpClient?
Ответы
Ответ 1
Основываясь на моих выводах, я пришел к выводу, что HttpClient является очень ограничительным с точки зрения правил протокола. Я также нашел отражение в DLL реализации, и я не мог найти ничего, что могло бы указывать на то, что оно допускает нарушения протокола.
Запросы GET не должны содержать заголовки типа контента, и HttpClient применяет это правило.
Я думаю, что сообщение об исключении, когда вы пытаетесь установить заголовок типа контента, самоописательно:
System.InvalidOperationException: Неправильное имя заголовка. Убедитесь, что заголовки запросов используются с HttpRequestMessage, заголовками ответов с HttpResponseMessage и заголовками содержимого с объектами HttpContent.
Также, если вы используете настройку тела контента, вы получите еще одно самоописательное сообщение:
System.Net.ProtocolViolationException: Не удается отправить контент-тело с помощью этого типа.
Поскольку вы готовы нарушать правила HTTP для запросов GET, я уверен, что ваш единственный вариант - придерживаться менее ограничительного WebClient, который работает в этом сценарии.
Ответ 2
Возможно - и очень грязно - переопределить поведение библиотеки с небольшим количеством размышлений и введя DelegatingHandler
, который вы даете в качестве аргумента конструктору HttpClient
. Смотрите код ниже.
public class HmacAuthenticatingHandler : DelegatingHandler
{
public HmacAuthenticatingHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// HACK: Set 'Content-Type' even for GET requests
var invalidHeaders = (HashSet<string>)typeof(HttpHeaders)
// use "_invalidHeaders" for System.Net.Http v2.2+
.GetField("invalidHeaders", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(request.Headers);
invalidHeaders.Remove("Content-Type");
request.Headers.Remove("Content-Type");
request.Headers.Add("Content-Type", "application/json");
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
Ответ 3
Несмотря на то, что сейчас вам не помогает, похоже, что будущая версия .NET Framework может поддерживать этот тип нарушения протокола с добавлением AddWithoutValidation:
https://msdn.microsoft.com/en-us/library/hh204926
Ответ 4
Вы пытались добавить заголовки в заголовок содержимого (как указано в заголовке запроса)
см. здесь