.net - HttpWebRequest 未发送所有 cookie

标签 .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” header
  • 容器保存所有正确的 Cookie(总共 5 个)

什么不起作用:

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

未发送的cookie是这个:

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

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

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

如有任何帮助,我们将不胜感激!

最佳答案

这是 CookieContainer 中常见的已知错误:Link Here 适用于 4.0 以下的 .Net 版本

注意 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

当 URL 格式类似于 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];
            }
        }
    }
    

所有功劳都归功于 CallMeLaNN 的解决方案

关于.net - HttpWebRequest 未发送所有 cookie,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14523811/

相关文章:

.net - 如何使用 C# ODP.NET 中的 Oracle Ref Cursor 作为 ReturnValue 参数,而不使用存储函数或过程?

c# - 复制 KeyedCollection 的最快方法

vb.net - 无法修复错误 "Could not load System.Net.Http, Version=4.2.0.0"

javascript - 从安全 Angular 来看,本地存储相对于 Cookie 有何优势?

javascript - JS |Xss防御题

c# - 使用 RegEx 进行多模式匹配

c# - 没有数据的IEnumerable

c# - Visual Studio 中的折叠区域

vb.net - 将选项卡式文本转换为 TreeView

javascript - IE11/Windows 10 => 对象不支持属性或方法 'includes'