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

我在努力弄清楚这里有什么问题。 我正在发送登录信息,我可以在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(); 

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

这是Set-Cookie Header值:

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

当我在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])); } } } 

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

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

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

在此答案中使用CookieContainer 。 这些正则表达式对我来说绊倒的是expires=Tue, ...的逗号。

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

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

 //... using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { request.FixCookies(response); //... 

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 getCookieDomainIfItIsMissingInCookie) { bool secure = false; bool httpOnly = false; string domainFromCookie = null; string path = null; string expiresString = null; Dictionary cookiesValues = new Dictionary(); 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; } } } 

这可能有点晚,但你可以使用函数SetCookies

 var cHeader = responce.Headers.Get("Set-Cookie"); var cookie = new CookieContainer(); cookie.SetCookies(new Uri("[...]"), cHeader); 

我知道这个问题很老,但我遇到了一些正确解析“Set-Cookie”标题的代码。 它处理以逗号分隔的cookie,并提取每个cookie的名称,过期,路径,值和域。

这段代码比微软自己的cookie解析器效果更好,这正是官方cookie解析器应该做的事情。 我没有任何线索,为什么微软还没有解决这个问题,因为这是一个非常普遍的问题。

这是原始代码: http : //snipplr.com/view/4427/

我在这里发布它,以防链接在某些时候出现故障:

 public static CookieCollection GetAllCookiesFromHeader(string strHeader, string strHost) { ArrayList al = new ArrayList(); CookieCollection cc = new CookieCollection(); if (strHeader != string.Empty) { al = ConvertCookieHeaderToArrayList(strHeader); cc = ConvertCookieArraysToCookieCollection(al, strHost); } return cc; } private static ArrayList ConvertCookieHeaderToArrayList(string strCookHeader) { strCookHeader = strCookHeader.Replace("\r", ""); strCookHeader = strCookHeader.Replace("\n", ""); string[] strCookTemp = strCookHeader.Split(','); ArrayList al = new ArrayList(); int i = 0; int n = strCookTemp.Length; while (i < n) { if (strCookTemp[i].IndexOf("expires=", StringComparison.OrdinalIgnoreCase) > 0) { al.Add(strCookTemp[i] + "," + strCookTemp[i + 1]); i = i + 1; } else { al.Add(strCookTemp[i]); } i = i + 1; } return al; } private static CookieCollection ConvertCookieArraysToCookieCollection(ArrayList al, string strHost) { CookieCollection cc = new CookieCollection(); int alcount = al.Count; string strEachCook; string[] strEachCookParts; for (int i = 0; i < alcount; i++) { strEachCook = al[i].ToString(); strEachCookParts = strEachCook.Split(';'); int intEachCookPartsCount = strEachCookParts.Length; string strCNameAndCValue = string.Empty; string strPNameAndPValue = string.Empty; string strDNameAndDValue = string.Empty; string[] NameValuePairTemp; Cookie cookTemp = new Cookie(); for (int j = 0; j < intEachCookPartsCount; j++) { if (j == 0) { strCNameAndCValue = strEachCookParts[j]; if (strCNameAndCValue != string.Empty) { int firstEqual = strCNameAndCValue.IndexOf("="); string firstName = strCNameAndCValue.Substring(0, firstEqual); string allValue = strCNameAndCValue.Substring(firstEqual + 1, strCNameAndCValue.Length - (firstEqual + 1)); cookTemp.Name = firstName; cookTemp.Value = allValue; } continue; } if (strEachCookParts[j].IndexOf("path", StringComparison.OrdinalIgnoreCase) >= 0) { strPNameAndPValue = strEachCookParts[j]; if (strPNameAndPValue != string.Empty) { NameValuePairTemp = strPNameAndPValue.Split('='); if (NameValuePairTemp[1] != string.Empty) { cookTemp.Path = NameValuePairTemp[1]; } else { cookTemp.Path = "/"; } } continue; } if (strEachCookParts[j].IndexOf("domain", StringComparison.OrdinalIgnoreCase) >= 0) { strPNameAndPValue = strEachCookParts[j]; if (strPNameAndPValue != string.Empty) { NameValuePairTemp = strPNameAndPValue.Split('='); if (NameValuePairTemp[1] != string.Empty) { cookTemp.Domain = NameValuePairTemp[1]; } else { cookTemp.Domain = strHost; } } continue; } } if (cookTemp.Path == string.Empty) { cookTemp.Path = "/"; } if (cookTemp.Domain == string.Empty) { cookTemp.Domain = strHost; } cc.Add(cookTemp); } return cc; } 

正确的方法是在检索响应之前设置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. 

您无需手动解析SetCookie