【问题标题】:Mapping Header cookie string to CookieCollection and vice versa将 Header cookie 字符串映射到 CookieCollection,反之亦然
【发布时间】:2011-06-15 03:01:02
【问题描述】:

考虑使用此标头的 Web 响应:

Set-Cookie: sample=testCookie; Domain=.sample.com; Expires=Tue, 25-Jan-2012 00:49:29 GMT; Path=/

此标头将映射到.NET 中的CookieCollection。而且当我们处理CookieCollection 时,它最终会转换成这样的header string

我正在寻找一种纯粹以两种方式进行这种转换的方法。当然.NET 有它在它的内部库中。我相信任何从文本构造对象模型的类,反之亦然,都应该支持两种方法(这里是CookieCollection):

// Creating cookie collection from header text
CookieCollection.TryParse(cookieHeaderString, out myCookieCollection);
// and getting the final header which would be sent by request
String cookieHeaderString = myCookieCollection.GetCookieHeaderString();

如何使用CookieCollection 实现这一目标?

【问题讨论】:

    标签: c# cookies http-headers


    【解决方案1】:

    我想你正在寻找CookieContainer。请参阅 SetCookies 方法。

    【讨论】:

    • CookieContainer.GetCookieHeader() omly 返回 key=value 和其他文本,如 domainpath 被遗漏。
    • SetCookies 似乎忽略了过期的 cookie
    • 没人在找这个。
    【解决方案2】:

    我知道这已经得到解答,但您可能希望使用以下代码: 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)
                {
                    strDNameAndDValue = strEachCookParts[j];
                    if (strDNameAndDValue != string.Empty)
                    {
                        NameValuePairTemp = strDNameAndDValue.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;
    }
    

    此代码将读取以逗号分隔的 cookie,并正确解析每个 cookie 的所有部分,包括名称、到期时间、路径、值和域。

    【讨论】:

    • 这个解决方案对我很有效。 CookieContainer.SetCookies 方法引发了一个解析错误,我在一个 wordpress 网站上抱怨“path=/wp-content/plugins”。 “手动”解析 cookie 并将 CookieCollection 添加到 CookieContainer 是唯一的出路。你的代码为我节省了很多时间。非常感谢。
    • 如果 cookie 值包含逗号会失败吗?
    • 我很欣赏并正在使用您的代码,我说这对任何需要它的人都有帮助;逗号分隔似乎输给了分号,请参阅那里对“标准”的讨论(浏览器似乎发送分号)stackoverflow.com/questions/2394561/…
    • 我还建议返回List&lt;Cookie&gt;,因为此解决方案不支持handling multiple cookies with the same name,最终会按其名称合并它们。
    • 现在,这就是我们要找的。​​span>
    【解决方案3】:

    这是我用来执行此操作的扩展类。

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Net;
    using System.Text.RegularExpressions;
    using System.Web;
    
    namespace YourProjectName.Extensions
    {
         public static class HttpCookieExtension
        {
             static Regex rxCookieParts = new Regex(@"(?<name>.*?)\=(?<value>.*?)\;|(?<name>\bsecure\b|\bhttponly\b)", RegexOptions.Compiled |RegexOptions.Singleline|RegexOptions.IgnoreCase);
             static Regex rxRemoveCommaFromDate = new Regex(@"\bexpires\b\=.*?(\;|$)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
             public static bool GetHttpCookies(this NameValueCollection collection, int index , out List<HttpCookie> cookies)
             {
                 cookies = new List<HttpCookie>();
    
                 if (collection.AllKeys[index].ToLower() != "set-cookie") return false;
                 try
                 {
    
                     string rawcookieString = rxRemoveCommaFromDate.Replace(collection[index],  new MatchEvaluator(RemoveComma));
    
                     string[] rawCookies = rawcookieString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
    
                     foreach (var rawCookie in rawCookies)
                     {
                        cookies.Add(rawCookie.ToHttpCookie());
                     }
                     return true;
                 }
                 catch (Exception)
                 {
    
                     return false;
                 }
             }
    
    
             public static bool GetHttpCookiesFromHeader(this string cookieHeader, out CookieCollection cookies)
             {
                 cookies = new CookieCollection();
    
    
                 try
                 {
    
                     string rawcookieString = rxRemoveCommaFromDate.Replace(cookieHeader, new MatchEvaluator(RemoveComma));
    
                     string[] rawCookies = rawcookieString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
    
                     if (rawCookies.Length == 0)
                     {
                         cookies.Add(rawcookieString.ToCookie());
                     }
                     else
                     {
                        foreach (var rawCookie in rawCookies)
                        {
                            cookies.Add(rawCookie.ToCookie());
                        }
                     }
    
                     return true;
                 }
                 catch (Exception)
                 {
                     throw;
                 }
             }
    
    
    
    
             public static Cookie ToCookie(this string rawCookie)
             {
    
                 if (!rawCookie.EndsWith(";")) rawCookie += ";";
    
                 MatchCollection maches = rxCookieParts.Matches(rawCookie);
    
                 Cookie cookie = new Cookie(maches[0].Groups["name"].Value.Trim(), maches[0].Groups["value"].Value.Trim());
    
                 for (int i = 1; i < maches.Count; i++)
                 {
                     switch (maches[i].Groups["name"].Value.ToLower().Trim())
                     {
                         case "domain":
                             cookie.Domain = maches[i].Groups["value"].Value;
                             break;
                         case "expires":
    
                             DateTime dt;
    
                             if (DateTime.TryParse(maches[i].Groups["value"].Value, out dt))
                             {
                                 cookie.Expires = dt;
                             }
                             else
                             {
                                 cookie.Expires = DateTime.Now.AddDays(2);
                             }
                             break;
                         case "path":
                             cookie.Path = maches[i].Groups["value"].Value;
                             break;
                         case "secure":
                             cookie.Secure = true;
                             break;
                         case "httponly":
                             cookie.HttpOnly = true;
                             break;
                     }
                 }
                 return cookie;
    
    
             }
    
             public static HttpCookie ToHttpCookie(this string rawCookie)
             {
                 MatchCollection maches = rxCookieParts.Matches(rawCookie);
    
                 HttpCookie cookie = new HttpCookie(maches[0].Groups["name"].Value, maches[0].Groups["value"].Value);
    
                 for (int i = 1; i < maches.Count; i++)
                 {
                     switch (maches[i].Groups["name"].Value.ToLower().Trim())
                     {
                         case "domain":
                             cookie.Domain = maches[i].Groups["value"].Value;
                             break;
                         case "expires":
    
                             DateTime dt;
    
                             if (DateTime.TryParse(maches[i].Groups["value"].Value, out dt))
                             {
                                 cookie.Expires = dt;
                             }
                             else
                             {
                                 cookie.Expires = DateTime.Now.AddDays(2);
                             }
                             break;
                         case "path":
                             cookie.Path = maches[i].Groups["value"].Value;
                             break;
                         case "secure":
                             cookie.Secure = true;
                             break;
                         case "httponly":
                             cookie.HttpOnly = true;
                             break;
                     }
                 }
                 return cookie;
             }
    
             private static KeyValuePair<string, string> SplitToPair(this string input)
             {
                string[]  parts= input.Split(new char[] {'='},StringSplitOptions.RemoveEmptyEntries);
                return new KeyValuePair<string, string>(parts[0],parts[1]);
             }
    
             private static string RemoveComma(Match match)
             {
                 return match.Value.Replace(',', ' ');
             }
        }
    
    }
    

    【讨论】:

    • 什么是 HttpCookie?
    猜你喜欢
    • 2011-06-24
    • 2012-03-06
    • 2015-12-09
    • 2014-11-18
    • 1970-01-01
    • 2018-02-05
    • 2017-11-17
    • 1970-01-01
    相关资源
    最近更新 更多