尽管Set-Cookie Header(无重定向),HttpWebResponse.Cookies为空

Bra*_*rad 24 c# cookies httpwebrequest

我在努力弄清楚这里有什么问题.我正在发送登录信息,我可以在Header中看到具有正确值的Set-Cookie,但Cookies集合没有被填满.

这是HTTPS,登录自动重定向,但我使用AllowAutoRedirect = false禁用它以尝试解决此问题.

在此屏幕截图中,您可以轻松查看调试信息,并且应该设置cookie.我将我的httpWebRequest.Cookie设置为新的CookieCollection.

右键单击并选择查看图像以查看完整大小.

HttpWebRequest httpRequest;
CookieContainer reqCookies = new CookieContainer();
string url = "https://example.com";
string[] email = user.Split('@');
email[0] = System.Web.HttpUtility.UrlEncode(email[0]);
user = email[0] + "@" + email[1];
pass = System.Web.HttpUtility.UrlEncode(pass);

string postData = "email=" + user + "&password=" + pass;
byte[] byteData = Encoding.UTF8.GetBytes(postData);

httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.Referer = url;
httpRequest.CookieContainer = reqCookies;
httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1003.1 Safari/535.19";
httpRequest.Accept = "text/html, application/xhtml+xml, */*";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.ContentLength = byteData.Length;
using (Stream postStream = httpRequest.GetRequestStream())
{
    postStream.Write(byteData, 0, byteData.Length);
    postStream.Close();
}

httpRequest.AllowAutoRedirect = false;
HttpWebResponse b = (HttpWebResponse)httpRequest.GetResponse();
Run Code Online (Sandbox Code Playgroud)

尝试连接到http://www.yahoo.com的完全相同的代码,并将cookie放入我的收藏中...... Argh ......

这是Set-Cookie Header值:

S = 541E2101-B768-45C8-B814-34A00525E50F; 域= example.com; 路径= /; 版本= 1

Nic*_*s78 19

当我在C#中读取由C#ASP.NET应用程序创建的Cookie时,我也发现了这个问题...;)

不确定它是否与它有关,但我发现在我的情况下设置的两个Cookie都写在一个Set-Cookie标头中,cookie的有效负载用逗号分隔.所以我调整了AppDeveloper的解决方案来处理这个多cookie问题,以及修复我在评论中提到的名称/值.

private static void fixCookies(HttpWebRequest request, HttpWebResponse response) 
{
    for (int i = 0; i < response.Headers.Count; i++)
    {
        string name = response.Headers.GetKey(i);
        if (name != "Set-Cookie")
            continue;
        string value = response.Headers.Get(i);
        foreach (var singleCookie in value.Split(','))
        {
            Match match = Regex.Match(singleCookie, "(.+?)=(.+?);");
            if (match.Captures.Count == 0)
                continue;
            response.Cookies.Add(
                new Cookie(
                    match.Groups[1].ToString(), 
                    match.Groups[2].ToString(), 
                    "/", 
                    request.Host.Split(':')[0]));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 快速修复"coki1 = val1; expires = sat,星期一2017;域名:asdf.com,coki2 = val2; expires = sat,星期一2017;域名:asdf.com,".逗号也用于过期日期.su it messes up split(",")将此添加为临时修复值= Regex.Replace(value,"(e | E)xpires =(.+?)(; | $)|(P | p)ath =( .+?);",""); (3认同)
  • 正如@blackholeearth0_gmail 所提到的,从逗号拆分会产生额外的错误cookie,因为在`expires` 标题`Wed, 04-Apr-18` 中有一个逗号 (2认同)

PaR*_*RaJ 15

看起来Set-Cookie网站发送的标题格式不正确(不是应该采用的典型格式).

在这种情况下,您需要手动解析cookie并将其解析为CookieContainer.

for (int i = 0; i < b.Headers.Count; i++)
{
    string name = b.Headers.GetKey(i);
    string value = b.Headers.Get(i);
    if (name == "Set-Cookie")
    {
        Match match = Regex.Match(value, "(.+?)=(.+?);");
        if (match.Captures.Count > 0)
        {
            reqCookies.Add(new Cookie(match.Groups[1].Value, match.Groups[2].Value, "/", "example.com"));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 啊,是的,这是真的.但是,这有点独立于你正在添加一个名为"Set-Cookie"的cookie,不是吗? (2认同)

小智 7

CookieContainer这个答案中使用as .这些正则表达式让我感到惊讶的是一个逗号expires=Tue, ....


Sam*_*Sam 7

正确的方法是CookieContainer在获取响应之前设置成员:

var request = (HttpWebRequest)HttpWebRequest.Create(..);
request.CookieContainer = new CookieContainer();

var response = request.GetResponse();
// ..response.Cookies will now contain the cookies sent back by the server.
Run Code Online (Sandbox Code Playgroud)

您无需手动解析SetCookie


Ana*_*nyi 5

看看其他答案我改进了错误的cookie处理.与那些答案不同,这个答案会自动处理所有cookie属性(例如过期,安全等)并适用于所有范围的cookie(即使有超过1个不正确的cookie).

它作为扩展方法实现,可以通过以下方式使用:

//...
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                request.FixCookies(response);
//...
Run Code Online (Sandbox Code Playgroud)

FixCookies() 扩展方法:

using System;
using System.Collections.Generic;
using System.Net;

namespace AG.WebHelpers
{
    static public class ExtensionMethods
    {
        static public void FixCookies(this HttpWebRequest request, HttpWebResponse response)
        {
            for (int i = 0; i < response.Headers.Count; i++)
            {
                string name = response.Headers.GetKey(i);
                if (name != "Set-Cookie")
                    continue;
                string value = response.Headers.Get(i);
                var cookieCollection = ParseCookieString(value, () => request.Host.Split(':')[0]);
                response.Cookies.Add(cookieCollection);
            }
        }

        static private CookieCollection ParseCookieString(string cookieString, Func<string> getCookieDomainIfItIsMissingInCookie)
        {
            bool secure = false;
            bool httpOnly = false;

            string domainFromCookie = null;
            string path = null;
            string expiresString = null;

            Dictionary<string, string> cookiesValues = new Dictionary<string, string>();

            var cookieValuePairsStrings = cookieString.Split(';');
            foreach(string cookieValuePairString in cookieValuePairsStrings)
            {
                var pairArr = cookieValuePairString.Split('=');
                int pairArrLength = pairArr.Length;
                for (int i = 0; i < pairArrLength; i++)
                {
                    pairArr[i] = pairArr[i].Trim();
                }
                string propertyName = pairArr[0];
                if (pairArrLength == 1)
                {
                    if (propertyName.Equals("httponly", StringComparison.OrdinalIgnoreCase))
                        httpOnly = true;
                    else if (propertyName.Equals("secure", StringComparison.OrdinalIgnoreCase))
                        secure = true;
                    else
                        throw new InvalidOperationException(string.Format("Unknown cookie property \"{0}\". All cookie is \"{1}\"", propertyName, cookieString));
                    continue;
                }

                string propertyValue = pairArr[1];
                if (propertyName.Equals("expires", StringComparison.OrdinalIgnoreCase))
                    expiresString = propertyValue;
                else if (propertyName.Equals("domain", StringComparison.OrdinalIgnoreCase))
                    domainFromCookie = propertyValue;
                else if (propertyName.Equals("path", StringComparison.OrdinalIgnoreCase))
                    path = propertyValue;
                else
                    cookiesValues.Add(propertyName, propertyValue);
            }

            DateTime expiresDateTime;
            if (expiresString != null)
            {
                expiresDateTime = DateTime.Parse(expiresString);
            }
            else
            {
                expiresDateTime = DateTime.MinValue;
            }
            if (string.IsNullOrEmpty(domainFromCookie))
            {
                domainFromCookie = getCookieDomainIfItIsMissingInCookie();
            }

            CookieCollection cookieCollection = new CookieCollection();
            foreach (var pair in cookiesValues)
            {
                Cookie cookie = new Cookie(pair.Key, pair.Value, path, domainFromCookie);
                cookie.Secure = secure;
                cookie.HttpOnly = httpOnly;
                cookie.Expires = expiresDateTime;

                cookieCollection.Add(cookie);
            }
            return cookieCollection;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)