HttpWebRequest不发送所有cookie

时间:2013-01-25 14:28:48

标签: .net vb.net cookies httpwebrequest

我正在尝试让我的应用程序在外部网站上执行登录操作。我使用以下代码:

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

什么有效:

  • 回复中包含所有正确的“Set-Cookie”标题
  • 容器保存所有正确的Cookie(总共5个)

什么行不通:

  • 容器正确检索所有Cookie。但并非所有cookie都会在下一次请求时发送。正确设置了4个cookie,但未发送最重要的cookie。

未发送的cookie就是这个:

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

此Cookie与正确发送的Cookie之间的唯一区别是,其中包含“Version = 1”和“Discard”...

有没有人知道为什么除了上面提到的所有检索到的cookie之外都会被发送?

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

这是CookieContainer中常见的已知错误:Link Here for .Net version 4.0以下

注意Set-Cookie标头的域名:

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

当网址格式类似于http://marktplaats.nl/...时,会发送Cookie#1 当URL格式类似于http://www.marktplaats.nl/...

时,将发送Cookie#2

因此问题


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

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

解决方案#1的实现,每当你创建一个CookieContainer实例时,只需调用一次方法

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

这里是解决方案#2:

  1. 请勿使用.Add(Cookie),仅使用.Add(Uri,Cookie)方法。
  2. 每次向容器添加cookie时调用BugFix_CookieDomain 在使用.GetCookie之前或系统使用容器之前。

    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];
            }
        }
    }
    
  3. CallMeLaNN

    解决方案的所有积分

答案 1 :(得分:1)

决定为此/类似案例发布另一个解决方法,以防有人发现它有用。

我遇到了同样的问题,收到了三个Cookie,只有两个显示为从下一个网络请求发送的。我做了一些调试,发现我的错误不是域本身,因为之前的答案表明 - 在我的情况下,问题是返回的第三个cookie并且未在后续请求中重用被设置为HTTPS重定向,它将“Secure”属性设置为true。所以 我所要做的就是将下一个请求网址从http:// ....更改为https:// .... ,然后所有的cookie都是发送过来,一切正常。

希望它有所帮助!