Jak ustawić plik cookie w HttpRequestMessage firmy HttpClient

247

Próbuję użyć interfejsu API sieci Web, HttpClientaby zrobić post do punktu końcowego, który wymaga zalogowania się w postaci pliku cookie HTTP, który identyfikuje konto (jest to tylko coś, co zostało #ifdefusunięte z wersji wydania).

Jak dodać plik cookie do HttpRequestMessage?

George Mauer
źródło

Odpowiedzi:

374

Oto jak ustawić niestandardową wartość pliku cookie dla żądania:

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();
}
Darin Dimitrov
źródło
2
handler może zostać usunięty z instrukcji, zostanie usunięty, gdy klient HTTP zostanie usunięty.
Kimi
17
Kimi ma rację, ale także nie powinieneś zawijać swojego HttpClient przy użyciu. aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Robert McLaws
9
UWAGA: jeśli użyjesz tylko 1 instancji HttpClient do wykonania kilku żądań, pliki cookie korzystające z CookieContainer będą buforowane. Niebezpieczne dla użytkownika uzyskanie pliku cookie od innego użytkownika.
Acaz Souza
31
„HttpClient ma zostać utworzony raz i ponownie użyty przez cały okres użytkowania aplikacji. Zwłaszcza w aplikacjach serwerowych, tworzenie nowej instancji HttpClient dla każdego żądania wyczerpuje liczbę gniazd dostępnych pod dużym obciążeniem ...” Stąd: asp .net / web-api /
Overview
4
@SergeyT, więc co zrobić, gdy trzeba wykonać osobne sesje do tego samego zasobu? :)
AgentFire,
337

W większości przypadków zaakceptowana odpowiedź to właściwy sposób. Istnieją jednak sytuacje, w których chcesz ręcznie ustawić nagłówek pliku cookie. Zwykle po ustawieniu nagłówka „Cookie” jest on ignorowany, ale HttpClientHandlerdzieje się tak dlatego, że domyślnie używa jego CookieContainerwłaściwości do plików cookie. Jeśli wyłączysz które następnie ustawiając UseCookiessię falsemożna ustawić nagłówki cookies ręcznie i pojawią się one we wniosku, np

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();
}
Greg Beech
źródło
44
Goniłem od kilku dni błąd, w którym żądania wysłane za pomocą SendAsync nie wysłały nagłówka pliku cookie; pomogło mi to uświadomić sobie, że jeśli nie ustawisz UseCookies = false w module obsługi, nie tylko użyje kontenera plików cookie, ale także po cichu zignoruje pliki cookie zapisane w nagłówkach żądania! Dziękuję bardzo!
Fernando Neira,
14
Ta odpowiedź jest niezwykle pomocna dla każdego, kto próbuje użyć HttpClient jako serwera proxy!
cchamberlain
3
Spróbuj tego teraz ... jeśli to zadziała ... zasługujesz na dobry kanadyjski uścisk.
Maxime Rouiller,
11
UWAGA: jeśli użyjesz tylko 1 instancji HttpClient do wykonania kilku żądań, pliki cookie korzystające z CookieContainer będą buforowane. Niebezpieczne dla użytkownika uzyskanie pliku cookie od innego użytkownika.
Acaz Souza
9
Ta głupia rzecz powinna rzucić wyjątek, gdy ktoś próbuje dodać nagłówek „Cookie” zamiast go po cichu zgubić. Kosztowało mnie godzinę życia. Dzięki za rozwiązanie.
stmax 20.01.2018
5

Po spędzeniu godzin na tym problemie żadna z powyższych odpowiedzi nie pomogła mi, więc znalazłem naprawdę przydatne narzędzie.

Po pierwsze, użyłem Fiddler 4 firmy Telerik do szczegółowego przestudiowania moich żądań internetowych

Po drugie, natknąłem się na tę przydatną wtyczkę do Fiddler:

https://github.com/sunilpottumuttu/FiddlerGenerateHttpClientCode

Po prostu wygeneruje dla Ciebie kod C #. Przykładem było:

        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;

Zauważ, że musiałem skomentować dwa wiersze, ponieważ ta wtyczka nie jest jeszcze całkowicie idealna, ale mimo to zadziałała.

WYŁĄCZENIE ODPOWIEDZIALNOŚCI: w żadnym wypadku nie jestem związany ani wspierany przez Telerik ani autora wtyczki.

Amir No-Family
źródło
2
Jest to w zasadzie ta sama odpowiedź, co ta , jedyną częścią związaną z plikami cookie jest ostatnie dodanie nagłówka. Zwróć uwagę na wszystkie zastrzeżenia w tej odpowiedzi
George Mauer,
4

Dla mnie proste rozwiązanie działa w celu ustawienia plików cookie w obiekcie 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
źródło
Zauważ, że zaakceptowana odpowiedź ma masę o wiele więcej i obsługuje znacznie więcej warunków brzegowych niż ta. Można go używać do robienia rzeczy takich jak tylko HTTP lub ciasteczka o zasięgu, ciasteczka wielowartościowe itp. Druga najwyżej oceniana odpowiedź proponuje tę samą metodę, ale z dużo większym kontekstem i wyjaśnieniami
George Mauer
@GeorgeMauer może mieć rację. Oboje tworzą httpClient z „HttpClient (handler)”. W moim przypadku tworzę _httpClient z httpClientPool.GetOrCreateHttpClient ()
Waqar UlHaq
1
Ale tak naprawdę nie pokazujesz tego w swojej odpowiedzi, ani nie wyjaśniasz różnicy ani korzyści (to nie jest tak naprawdę pytanie, ale nie martwię się o to). Nie staram się być niegrzeczny, ważne jest, aby wyjaśnić, komu ta odpowiedź byłaby pomocna, na co inni nie lepiej by pomogli.
George Mauer,