Walczę z próbą wyciągnięcia cookie z odpowiedzi z HttpClient w .net 4.5

107

Mam następujący kod, który działa pomyślnie. Nie mogę dowiedzieć się, jak wyjąć plik cookie z odpowiedzi. Moim celem jest to, aby móc ustawić pliki cookie w żądaniu i uzyskać pliki cookie z odpowiedzi. Myśli?

private async Task<string> Login(string username, string password)
{
    try
    {
        string url = "http://app.agelessemail.com/account/login/";
        Uri address = new Uri(url);
        var postData = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("username", username),
            new KeyValuePair<string, string>("password ", password)
        };

        HttpContent content = new FormUrlEncodedContent(postData);
        var cookieJar = new CookieContainer();
        var handler = new HttpClientHandler
        {
            CookieContainer = cookieJar,
            UseCookies = true,
            UseDefaultCredentials = false
        };

        var client = new HttpClient(handler)
        {
            BaseAddress = address
        };


        HttpResponseMessage response = await client.PostAsync(url,content);
        response.EnsureSuccessStatusCode();
        string body = await response.Content.ReadAsStringAsync();
        return body;
    }
    catch (Exception e)
    {
        return e.ToString();
    }
}

Oto pełna odpowiedź:

HttpResponseMessage response = await client.PostAsync(url,content);
response.EnsureSuccessStatusCode();

Uri uri = new Uri(UrlBase);
var responseCookies = cookieJar.GetCookies(uri);
foreach (Cookie cookie in responseCookies)
{
    string cookieName = cookie.Name;
    string cookieValue = cookie.Value;
}
Peter Kellner
źródło
Czy z ciekawości mogę zapytać, dlaczego chcesz czytać ciasteczka na kliencie? Rozumiem, że pliki cookie służą do wysyłania informacji do serwera, a nie do zwracania informacji.
Darrel Miller
Używam zwróconego pliku cookie w połączeniach, które zwracają JSON, więc nie muszę wykonywać osobnego wywołania autoryzacyjnego dla każdego wywołania JSON. To znaczy, że mam dziennik połączeń / Home / GetData, który zwraca JSON, ale tylko wtedy, gdy jest autoryzowany. Na życzenie klienta dodaję ciasteczko, aby / Home / GetData odpowiadało. W przeciwnym razie powie „403” nieautoryzowane.
Peter Kellner
Ustawienie nagłówka autoryzacji jako nagłówka domyślnego jest prawie tak samo skuteczne i nieco bardziej standardowe. Po prostu nie ma sposobu, aby serwer automatycznie ustawił nagłówek auth w imieniu klienta.
Darrel Miller
1
dzięki za cynk Darrel. Czy masz jakieś przykłady tego, jak mogłoby to wyglądać w asp.net? Walczyłem z tym dla mojego monotouch, a teraz mojej aplikacji Windows Store. Byłbym szczęśliwy, gdyby istniał prosty sposób. Jest to uciążliwe, szczególnie w przypadku asynchronizacji i czekania teraz w aplikacjach sklepu Windows.
Peter Kellner

Odpowiedzi:

170

Aby dodać pliki cookie do żądania, wypełnij kontener plików cookie przed żądaniem za pomocą CookieContainer.Add(uri, cookie). Po wysłaniu żądania kontener plików cookie zostanie automatycznie wypełniony wszystkimi plikami cookie z odpowiedzi. Następnie możesz wywołać GetCookies (), aby je odzyskać.

CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;

HttpClient client = new HttpClient(handler);
HttpResponseMessage response = client.GetAsync("http://google.com").Result;

Uri uri = new Uri("http://google.com");
IEnumerable<Cookie> responseCookies = cookies.GetCookies(uri).Cast<Cookie>();
foreach (Cookie cookie in responseCookies)
    Console.WriteLine(cookie.Name + ": " + cookie.Value);

Console.ReadLine();
Despertar
źródło
8
Uwaga: Po otrzymaniu początkowych plików cookie w pierwszym połączeniu, podczas uzyskiwania dostępu do jakichkolwiek stron z tej samej domeny, pliki cookie zostaną wysłane automatycznie, bez dodatkowych czynności.
Jahmic
Musisz dodać „using System.linq;”
Cabuxa.Mapache
^^ System.Linq jest wymagany tylko wtedy, gdy chcesz korzystać z metody .Cast <>, nie jest to wymagane do pobierania plików cookie, ale powinno to być oczywiste :)
MikeDub
Czy możliwe jest uzyskanie plików cookie w ten sam sposób, jeśli httpclientsą zbudowane z fabryki httpclient? tj. metoda konstruktora dodana do services.AddHttpClient
user3279954
w programie get Async utworzyliśmy już odniesienie do „google.com”, dlaczego musimy ponownie zadeklarować identyfikator URI z odniesieniem do niego?
Malcolm Salvador
7

Istnieje alternatywa, jeśli nie masz dostępu do HttpClienti nie możesz wstrzyknąć pliku CookieContainer. Działa to w .NET Core 2.2:

private string GetCookie(HttpResponseMessage message)
{
    message.Headers.TryGetValues("Set-Cookie", out var setCookie);
    var setCookieString = setCookie.Single();
    var cookieTokens = setCookieString.Split(';');
    var firstCookie = cookieTokens.FirstOrDefault();
    var keyValueTokens = firstCookie.Split('=');
    var valueString = keyValueTokens[1];
    var cookieValue = HttpUtility.UrlDecode(valueString);
    return cookieValue;
}
Rytis I
źródło
1
Genialne i surowe, ale właśnie to, czego potrzebuję ... Dobra robota, dzięki.
Vedran Mandić
5

Możesz łatwo uzyskać wartość cookie z podanym adresem URL.

private async Task<string> GetCookieValue(string url, string cookieName)
{
    var cookieContainer = new CookieContainer();
    var uri = new Uri(url);
    using (var httpClientHandler = new HttpClientHandler
    {
        CookieContainer = cookieContainer
    })
    {
        using (var httpClient = new HttpClient(httpClientHandler))
        {
            await httpClient.GetAsync(uri);
            var cookie = cookieContainer.GetCookies(uri).Cast<Cookie>().FirstOrDefault(x => x.Name == cookieName);
            return cookie?.Value;
        }
    }
}
Alper Ebicoglu
źródło