HttpWebRequest的未发送的所有CookieHttpWebRequest、Cookie

由网友(南顾生烟)分享简介:我试图让我的应用程序对外部网站进行登录操作。我用下面的code:昏暗ENC作为编码= Encoding.UTF8昏暗的数据为字节()=无昏暗的REQ作为HttpWebRequest的REQ = CTYPE(Net.WebRequest.Create(URL),Net.HttpWebRequest)req.Method...

我试图让我的应用程序对外部网站进行登录操作。我用下面的code:

 昏暗ENC作为编码= Encoding.UTF8
    昏暗的数据为字节()=无
    昏暗的REQ作为HttpWebRequest的

    REQ = CTYPE(Net.WebRequest.Create(URL),Net.HttpWebRequest)
    req.Method =方法
    req.Co​​okieContainer = CookieJar

    req.AllowAutoRedirect = FALSE
    如果方法=POST然后
        req.Co​​ntentType =应用/的X WWW的形式urlen codeD
        数据= enc.GetBytes(的PostData)
        如果Data.Length> 0然后
            req.Co​​ntentLength = Data.Length
            昏暗方通作为物流= req.GetRequestStream()
            newStream.Write(数据,0,Data.Length)
            newStream.Flush()
            newStream.Close()
        结束如果
    结束如果

    昏暗的响应,Net.HttpWebResponse = CTYPE(req.GetResponse(),Net.HttpWebResponse)

    昏暗ResponseStream作为IO.StreamReader =新IO.StreamReader(Response.GetResponseStream(),ENC)
    昏暗的HTML作为字符串= ResponseStream.ReadToEnd()

    Response.Close()
    ResponseStream.Close()

    返回HTML
 

什么工作:

的答复拥有所有正确的设置Cookie标题 在该容器中保存所有的权利饼干(共5)

有什么不工作:

所有cookie被正确地检索由容器。但是,并非所有的cookies沿蒙山下一个请求发送。 4饼干设置正确,但最重要的是不会被发送。

这是不发送的cookie是这个:

 设置Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.xxxxx.nl;Discard
 
浅谈Cookie HttpOnly那点事儿

此Cookie,并正确地发送饼干之间唯一的区别是,在它这其中有版本= 1和放弃...

没有任何人有任何想法,为什么所有检索到的cookie被发送,除了上面的那个?

任何帮助将是AP preciated!

解决方案

这是一个的CookieContainer常见的已知的bug:链接在这里 的.NET版本低于4.0 的

注意设置Cookie标头的域:

 曲奇#1  - >设置Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=marktplaats.nl;Discard
曲奇#2  - >设置Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.marktplaats.nl;Discard
 

当URL格式是这样的HTTP cookie#1发送://marktplaats.nl / ... //www.marktplaats.nl / ...

:当URL格式是这样的HTTP cookie#2发送

因此,问题

这里的解决方案#1:(更好的和容易的)

 类DomainComparer:StringComparer
    {
        公众覆盖INT比较(字符串x,y字符串)
        {
            如果(X == NULL ||ÿ== NULL)
            {
                返回StringComparer.OrdinalIgnoreCase.Compare(X,Y);
            }
            如果(x.StartsWith(WWW,StringComparison.OrdinalIgnoreCase))
            {
                X = x.Substring(4);
            }
            如果(y.StartsWith(WWW,StringComparison.OrdinalIgnoreCase))
            {
                Y = y.Substring(4);
            }
            返回StringComparer.OrdinalIgnoreCase.Compare(X,Y);
        }

        公众覆盖布尔等于(字符串x,y字符串)
        {
            返回比较(X,Y)== 0;
        }

        公众覆盖INT GetHash code(字符串OBJ)
        {
            如果(obj.StartsWith(WWW,StringComparison.OrdinalIgnoreCase))
            {
                物镜= obj.Substring(4);
            }
            返回StringComparer.OrdinalIgnoreCase.GetHash code(OBJ);
        }
    }

    ///<总结>
    ///这是一个hackfix为微软的bug,其中Cookie不会之间www.domain.com和domain.com共享
    ///< /总结>
    ///< PARAM NAME =CC>< /参数>
    静态无效ImproveCookieContainer(REF的CookieContainer CC)
    {
        哈希表的表=(哈希表)cc.GetType()。InvokeMember(
            m_domainTable
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance,
            空,CC,新的对象[] {});
        VAR比较器preperty = table.GetType()。getfield命令(_ keycomparer
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance);
        如果(比较器preperty!= NULL)
        {
            比较器preperty.SetValue(表中,新DomainComparer());
        }
    }
 

解#1,只要您创建的CookieContainer的实例只要调用方法一旦实施

 无效的主要()
{
    的CookieContainer cookieJar =新的CookieContainer();
    ImproveCookieContainer(REF cookieJar);
    //然后用它与WebRequest对象
}
 

这里的解决方案#2:

请不要使用。新增(饼干),只能使用。新增(URI,饼干)方法。

通话BugFix_CookieDomain每次添加一个cookie的容器或 在使用之前.GetCookie或之前系统使用的容器。

 私人无效BugFix_CookieDomain(的CookieContainer的CookieContainer)
{
    System.Type的_ContainerType = typeof运算(的CookieContainer);
    哈希表的表=(哈希表)_ContainerType.InvokeMember(m_domainTable
                               System.Reflection.BindingFlags.NonPublic |
                               System.Reflection.BindingFlags.GetField |
                               System.Reflection.BindingFlags.Instance,
                               空值,
                               的CookieContainer,
                               新对象[] {});
    ArrayList的键=新的ArrayList(table.Keys);
    的foreach(在钥匙串keyObj)
    {
        字符串键=(keyObj为字符串);
        如果(键[0] =='。')
        {
            字符串则newkey = key.Remove(0,1);
            表[则newkey] =表[keyObj]
        }
    }
}
 

要 CallMeLaNN

所有信贷的解决方案

I'm trying to have my application perform a login action on an external website. I use the following code:

Dim enc As Encoding = Encoding.UTF8
    Dim Data As Byte() = Nothing
    Dim req As HttpWebRequest

    req = CType(Net.WebRequest.Create(URL), Net.HttpWebRequest)
    req.Method = method
    req.CookieContainer = CookieJar

    req.AllowAutoRedirect = False
    If method = "POST" Then
        req.ContentType = "application/x-www-form-urlencoded"
        Data = enc.GetBytes(PostData)
        If Data.Length > 0 Then
            req.ContentLength = Data.Length
            Dim newStream As Stream = req.GetRequestStream()
            newStream.Write(Data, 0, Data.Length)
            newStream.Flush()
            newStream.Close()
        End If
    End If

    Dim Response As Net.HttpWebResponse = CType(req.GetResponse(), Net.HttpWebResponse)

    Dim ResponseStream As IO.StreamReader = New IO.StreamReader(Response.GetResponseStream(), enc)
    Dim Html As String = ResponseStream.ReadToEnd()

    Response.Close()
    ResponseStream.Close()

    Return Html

What works:

The responses have all the proper "Set-Cookie" headers The container saves all the right cookies (5 in total)

What doesn't work:

All cookies are correctly being retrieved by the container. But not all cookies are sent along whith the next request. 4 cookies are set correctly but the most important one is not sent.

The cookie that is not send is this one:

Set-Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.xxxxx.nl;Discard

The only difference between this cookie and the cookies that are correctly sent is that this one has "Version=1" and "Discard" in it...

Does anybody have any idea why all retrieved cookies are sent except for the one above?

Any help would be appreciated!

解决方案

This is a common known bug in CookieContainer : Link Here for .Net version below 4.0

Notice the Domain of Set-Cookie Header:

Cookie # 1 -> Set-Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=marktplaats.nl;Discard
Cookie # 2 -> Set-Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.marktplaats.nl;Discard

Cookie #1 is sent when the URL format is like http://marktplaats.nl/... Cookie #2 is sent when the URL format is like http://www.marktplaats.nl/...

Hence the problem

Here the solution # 1: (better and easy one)

    class DomainComparer : StringComparer
    {
        public override int Compare(string x, string y)
        {
            if (x == null || y == null)
            {
                return StringComparer.OrdinalIgnoreCase.Compare(x, y);
            }
            if (x.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
            {
                x = x.Substring(4);
            }
            if (y.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
            {
                y = y.Substring(4);
            }
            return StringComparer.OrdinalIgnoreCase.Compare(x, y);
        }

        public override bool Equals(string x, string y)
        {
            return Compare(x, y) == 0;
        }

        public override int GetHashCode(string obj)
        {
            if (obj.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
            {
                obj = obj.Substring(4);
            }
            return StringComparer.OrdinalIgnoreCase.GetHashCode(obj);
        }
    }

    /// <summary>
    /// this is a hackfix for microsoft bug, where cookies are not shared between www.domain.com and domain.com
    /// </summary>
    /// <param name="cc"></param>
    static void ImproveCookieContainer(ref CookieContainer cc)
    {
        Hashtable table = (Hashtable)cc.GetType().InvokeMember(
            "m_domainTable",
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance,
            null, cc, new object[] { });
        var comparerPreperty = table.GetType().GetField("_keycomparer", 
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance);
        if (comparerPreperty != null)
        {
            comparerPreperty.SetValue(table, new DomainComparer());
        }
    }

Implementation of Solution # 1, whenever you create a instance of CookieContainer just call the method once

void main()
{
    CookieContainer cookieJar = new CookieContainer();
    ImproveCookieContainer(ref cookieJar);
    // then use it with the WebRequest object
}

Here the solution # 2:

Don't use .Add(Cookie), Use only .Add(Uri, Cookie) method.

Call BugFix_CookieDomain each time you add a cookie to the container or before you use .GetCookie or before system use the container.

private void BugFix_CookieDomain(CookieContainer cookieContainer)
{
    System.Type _ContainerType = typeof(CookieContainer);
    Hashtable table = (Hashtable)_ContainerType.InvokeMember("m_domainTable",
                               System.Reflection.BindingFlags.NonPublic |
                               System.Reflection.BindingFlags.GetField |
                               System.Reflection.BindingFlags.Instance,
                               null,
                               cookieContainer,
                               new object[] { });
    ArrayList keys = new ArrayList(table.Keys);
    foreach (string keyObj in keys)
    {
        string key = (keyObj as string);
        if (key[0] == '.')
        {
            string newKey = key.Remove(0, 1);
            table[newKey] = table[keyObj];
        }
    }
}

All Credit for the solution to CallMeLaNN