Как мне установить cookie в HttpClient's HttpRequestMessage

247

Я пытаюсь использовать веб-интерфейсы API HttpClientдля публикации сообщения в конечной точке, для которой требуется вход в систему в виде HTTP-файла cookie, который идентифицирует учетную запись (это только то, что #ifdefисключено из версии выпуска).

Как мне добавить куки в HttpRequestMessage?

Джордж Мауэр
источник

Ответы:

374

Вот как вы можете установить пользовательское значение cookie для запроса:

var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("foo", "bar"),
        new KeyValuePair<string, string>("baz", "bazinga"),
    });
    cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
    var result = await client.PostAsync("/test", content);
    result.EnsureSuccessStatusCode();
}
Дарин димитров
источник
2
Обработчик может быть удален из оператора using, он будет удален при удалении http-клиента.
Кими
17
Кими прав, но вы также не должны использовать HttpClient. aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Роберт
9
ВНИМАНИЕ: если вы используете только 1 экземпляр HttpClient для выполнения нескольких запросов, файлы cookie, использующие CookieContainer, кэшируются. Опасно для пользователя получить cookie от другого пользователя.
Acaz Souza
31
«HttpClient предназначен для создания экземпляра один раз и повторного использования в течение всего жизненного цикла приложения. Особенно в серверных приложениях создание нового экземпляра HttpClient для каждого запроса приведет к исчерпанию количества сокетов, доступных при больших нагрузках ...» Отсюда: asp .net / web-api / обзор / продвинутый /…
SergeyT
4
@SergeyT, так что же делать, когда ему нужно делать отдельные сеансы вызовов на один и тот же ресурс? :)
AgentFire
337

Общепринятый ответ правильный способ сделать это в большинстве случаев. Однако в некоторых ситуациях вы хотите установить заголовок cookie вручную. Обычно, если вы устанавливаете заголовок «Cookie», он игнорируется, но это потому, что по HttpClientHandlerумолчанию используется его CookieContainerсвойство для файлов cookie. Если вы отключите это, то, установив UseCookiesдля falseвас, вы можете установить заголовки cookie вручную, и они появятся в запросе, например

var baseAddress = new Uri("http://example.com");
using (var handler = new HttpClientHandler { UseCookies = false })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
    var message = new HttpRequestMessage(HttpMethod.Get, "/test");
    message.Headers.Add("Cookie", "cookie1=value1; cookie2=value2");
    var result = await client.SendAsync(message);
    result.EnsureSuccessStatusCode();
}
Грег Бич
источник
44
В течение нескольких дней я преследовал ошибку, при которой запросы, отправленные с помощью SendAsync, не отправляли заголовок cookie; это помогло мне понять, что, если вы не установите UseCookies = false в обработчике, он будет не только использовать CookieContainer, но и молча игнорировать любые cookie, хранящиеся в заголовках запроса! Спасибо вам большое!
Фернандо Нейра
14
Этот ответ чрезвычайно полезен для всех, кто пытается использовать HttpClient в качестве прокси!
cchamberlain
3
Попробуй это сейчас ... если это сработает ... ты заслуживаешь хорошего канадского объятия.
Максим Роуиллер
11
ВНИМАНИЕ: если вы используете только 1 экземпляр HttpClient для выполнения нескольких запросов, файлы cookie, использующие CookieContainer, кэшируются. Опасно для пользователя получить cookie от другого пользователя.
Acaz Souza
9
Эта глупость должна вызывать исключение, когда кто-то пытается добавить заголовок «Cookie» вместо того, чтобы молча его потерять. Стоил мне час моей жизни. Спасибо за решение.
Stmax
5

Потратив несколько часов на эту проблему, ни один из приведенных выше ответов не помог мне, поэтому я нашел действительно полезный инструмент.

Во-первых, я использовал Fiddler 4 от Telerik для подробного изучения своих веб-запросов.

Во-вторых, я наткнулся на этот полезный плагин для Fiddler:

https://github.com/sunilpottumuttu/FiddlerGenerateHttpClientCode

Он просто сгенерирует код C # для вас. Пример был:

        var uriBuilder = new UriBuilder("test.php", "test");
        var httpClient = new HttpClient();


        var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uriBuilder.ToString());



        httpRequestMessage.Headers.Add("Host", "test.com");
        httpRequestMessage.Headers.Add("Connection", "keep-alive");
     //   httpRequestMessage.Headers.Add("Content-Length", "138");
        httpRequestMessage.Headers.Add("Pragma", "no-cache");
        httpRequestMessage.Headers.Add("Cache-Control", "no-cache");
        httpRequestMessage.Headers.Add("Origin", "test.com");
        httpRequestMessage.Headers.Add("Upgrade-Insecure-Requests", "1");
    //    httpRequestMessage.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
        httpRequestMessage.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36");
        httpRequestMessage.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        httpRequestMessage.Headers.Add("Referer", "http://www.translationdirectory.com/");
        httpRequestMessage.Headers.Add("Accept-Encoding", "gzip, deflate");
        httpRequestMessage.Headers.Add("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8");
        httpRequestMessage.Headers.Add("Cookie", "__utmc=266643403; __utmz=266643403.1537352460.3.3.utmccn=(referral)|utmcsr=google.co.uk|utmcct=/|utmcmd=referral; __utma=266643403.817561753.1532012719.1537357162.1537361568.5; __utmb=266643403; __atuvc=0%7C34%2C0%7C35%2C0%7C36%2C0%7C37%2C48%7C38; __atuvs=5ba2469fbb02458f002");


        var httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;

        var httpContent = httpResponseMessage.Content;
        string result = httpResponseMessage.Content.ReadAsStringAsync().Result;

Обратите внимание, что мне пришлось закомментировать две строки, так как этот плагин еще не совсем совершенен, но, тем не менее, он сделал свою работу.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не связан и не одобрен ни Telerik, ни автором плагина в любом случае.

Амир без семьи
источник
2
По сути, это тот же ответ, что и этот , единственная его часть, связанная с файлами cookie, - это последнее добавление заголовка. Обратите внимание на все предостережения в этом ответе
Джордж Мауэр
4

Для меня простое решение работает, чтобы установить куки в объект HttpRequestMessage .

protected async Task<HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage, CancellationToken cancellationToken = default(CancellationToken))
{
    requestMessage.Headers.Add("Cookie", $"<Cookie Name 1>=<Cookie Value 1>;<Cookie Name 2>=<Cookie Value 2>");

    return await _httpClient.SendAsync(requestMessage, cancellationToken).ConfigureAwait(false);
}
Waqar UlHaq
источник
Обратите внимание , что принятый ответ делает тонну больше и обрабатывает гораздо больше условий края , чем это. Его можно использовать для таких вещей, как http-файлы или cookie-файлы с определенными областями, многозначные cookie-файлы и т. Д. И т. Д. Во втором ответе с самым высоким рейтингом предлагается тот же метод, что и в этом, но с гораздо большим контекстом и пояснениями
Джордж Мауэр
@ GeorgeMauer может быть, вы правы. Оба они создают httpClient из «HttpClient (обработчик)». В моем случае я создаю _httpClient из httpClientPool.GetOrCreateHttpClient ()
Waqar UlHaq
1
Но вы на самом деле не показываете этого в своем ответе и не объясняете разницу или преимущества (на самом деле это не вопрос, но меня это не беспокоит). Я не пытаюсь быть грубым, просто важно понять, кому этот ответ будет полезен, а другим лучше не помогут.
Джордж Мауэр