【问题标题】:Struggling trying to get cookie out of response with HttpClient in .net 4.5在 .net 4.5 中尝试使用 HttpClient 使 cookie 无法响应
【发布时间】:2012-11-10 00:48:17
【问题描述】:

我有以下代码可以成功运行。我不知道如何从响应中获取 cookie。我的目标是我希望能够在请求中设置 cookie 并从响应中获取 cookie。想法?

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

这是完整的答案:

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

【问题讨论】:

  • 出于好奇,请问您为什么要在客户端读取cookies?我的理解是cookies是用来向服务器发送信息的,不是用来返回信息的。
  • 我在返回 JSON 的调用中使用返回的 cookie,这样我就不必为每个 JSON 调用进行单独的授权调用。也就是说,我有一个调用日志 /Home/GetData ,它返回 JSON 但只有在授权的情况下。在客户端请求中,我添加了 cookie,以便 /Home/GetData 响应。否则它会说“403”未授权。
  • 将授权标头设置为默认标头几乎同样有效且更加标准。服务器无法代表客户端自动设置 auth 标头。
  • 感谢达雷尔的提示。您是否有任何关于 asp.net 中的示例?我为我的 monotouch 和现在的 windows 商店应用程序而苦苦挣扎。如果有一个简单的方法,我会很高兴。这很痛苦,尤其是在 Windows 商店应用程序上使用 async 和 await now。

标签: c# async-await dotnet-httpclient


【解决方案1】:

要将 cookie 添加到请求中,请在请求之前使用 CookieContainer.Add(uri, cookie) 填充 cookie 容器。发出请求后,cookie 容器将自动填充来自响应的所有 cookie。然后,您可以调用 GetCookies() 来检索它们。

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

【讨论】:

  • 注意:在第一次调用中收到初始cookies后,当访问同域的任何页面时,cookies会自动发送,无需额外步骤。
  • 必须加上“using System.linq;”
  • 如果httpclient 是从 httpclient 工厂构建的,是否有可能以相同的方式获取 cookie?即添加到 services.AddHttpClient 的构建器方法
  • 在获取异步时我们已经引用了“google.com”,为什么我们需要再次声明一个引用它的URI?
  • @FireController1847 如果您想将其用作 IEnumerable,则只需进行转换,因为 GetCookies() 方法返回 CookieCollection,而不是 IEnumerable。如果您所做的只是使用上面代码中的循环,则不需要 IMO 强制转换,因为您仍然可以枚举 CookieCollection,因为它继承了 IEnumerable。
【解决方案2】:

如果您无权访问 HttpClient 并且无法注入 CookieContainer,则可以选择其他方法。这适用于 .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;
}

【讨论】:

  • 刚刚试过这个,var setCookieString = setCookie.Single(); 可能应该更改,因为setCookie 很可能有多个值,从而导致抛出异常。我最终添加了一个参数string cookieName,然后使用了setCookie.Single(x =&gt; x.StartsWith(cookieName));。这仍然假定请求的 cookie 存在。
【解决方案3】:

您可以使用给定的 URL 轻松获取 cookie 值。

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

【讨论】:

    【解决方案4】:

    并非在所有情况下都可以将httpClientHandler 添加到httpClient。例如,当您使用集成测试testServer.CreateClient() 或从IHttpClientFactory 注入httpClient 时。所以,我只是从标题中读取值。

        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 方法可以修改为与您的 cookie 属性完全匹配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-07
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 2013-02-19
      • 1970-01-01
      • 2022-08-13
      相关资源
      最近更新 更多