ChatGPT解决这个技术问题 Extra ChatGPT

Struggling trying to get cookie out of response with HttpClient in .net 4.5

I've got the following code that works successfully. I can't figure out how to get the cookie out of the response. My goal is that I want to be able to set cookies in the request and get cookies out of the response. Thoughts?

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();
    }
}

Here is the complete answer:

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;
}
Out of curiosity, can I ask why you want to read cookies on the client? My understanding is that cookies are used for sending information to the server, not for returning information.
I use the returned cookie on calls that return JSON so that I don't have to do a separate authorization call for each JSON call. That is to say, I have a call log /Home/GetData which returns JSON but only if authorized. On the client request, I add the cookie so that /Home/GetData will respond. Otherwise it will say "403" unauthorized.
Setting the authorization header as a default header is almost as effective and a bit more standard. There is just no way for the server to set the auth header automatically on behalf of the client.
thanks for the tip Darrel. Do you have any examples of what that might look like in asp.net? I struggled with this for my monotouch and now my windows store app. I'd be happy if there was a simple way. This is a pain, especially with async and await now on windows store apps.

D
Despertar

To add cookies to a request, populate the cookie container before the request with CookieContainer.Add(uri, cookie). After the request is made the cookie container will automatically be populated with all the cookies from the response. You can then call GetCookies() to retreive them.

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();

Note: After receiving the initial cookies in the first call, when accessing any pages from the same domain, the cookies will be sent automatically, no additional steps needed.
You must add "using System.linq;"
Is it possible to get cookies the same way if httpclient is built from the httpclient factory ? i.e builder method added to services.AddHttpClient
on get Async we already made a reference to "google.com", why do we need to declare a URI with a reference to it again?
@FireController1847 you only need to cast if you want to use it as a IEnumerable, as the GetCookies() method returns a CookieCollection, not IEnumerable. IMO the cast is not required if all you are doing is using the loop in the code above as you can still Enumerate over a CookieCollection due to it inheriting IEnumerable.
R
Rytis I

There's alternative if you don't have access to the HttpClient and can't inject the CookieContainer. This works in .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;
}

Just tried this, the var setCookieString = setCookie.Single(); should probably be changed as it is quite possible for setCookie to have multiple values and thus cause an exception to be thrown. I ended up adding a parameter string cookieName and then used setCookie.Single(x => x.StartsWith(cookieName));. This does still assume the requested cookie exists.
Set-Cookie header does have multiple values, they are separated by a semicolon(;), but normally there should be only a single Set-Cookie header
A
Alper Ebicoglu

You can easily get a cookie value with the given 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;
        }
    }
}

D
Deivydas Voroneckis

Not in every case you can add httpClientHandler to httpClient. For example, when you use integration tests testServer.CreateClient() or inject httpClient from IHttpClientFactory. So, I have simply read values from header.

    public static List<Cookie> GetCookies(this HttpResponseMessage message)
    {
        message.Headers.TryGetValues("Set-Cookie", out var cookiesHeader);
        var cookies = cookiesHeader.Select(cookieString => CreateCookie(cookieString)).ToList();
        return cookies;
    }

    private static Cookie CreateCookie(string cookieString)
    {
        var properties = cookieString.Split(';', StringSplitOptions.TrimEntries);
        var name = properties[0].Split("=")[0];
        var value = properties[0].Split("=")[1];
        var path = properties[2].Replace("path=", "");
        var cookie = new Cookie(name, value, path)
        {
            Secure = properties.Contains("secure"),
            HttpOnly = properties.Contains("httponly"),
            Expires = DateTime.Parse(properties[1].Replace("expires=", ""))
        };
        return cookie;
    }

CreateCookie method may be modified to exactly match your cookie properties.


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now