2

アプリケーションに外部 Web サイトでログイン アクションを実行させようとしています。次のコードを使用します。

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 の唯一の違いは、この Cookie には "Version=1" と "Discard" が含まれていることです...

上記のものを除いて、取得されたすべての Cookie が送信される理由を知っている人はいますか?

どんな助けでも大歓迎です!

4

2 に答える 2

2

これは、CookieContainer の一般的な既知のバグです。4.0未満の .Net バージョンのリンクはこちら

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

Cookie #1 は、URL 形式が次のような場合に送信されますhttp://marktplaats.nl/...
Cookie #2 は、URL 形式が次のような場合に送信されますhttp://www.marktplaats.nl/...

したがって、問題


ここで解決策#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 のインスタンスを作成するたびに、メソッドを 1 回呼び出すだけです。

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 をコンテナーに追加するたびに、または .GetCookie を使用する前、またはシステムがコンテナーを使用する前に、BugFix_CookieDomain を呼び出します。

    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のソリューションに対するすべての功績

于 2013-01-25T15:06:45.643 に答える
1

誰かが役に立つと思った場合に備えて、この/同様のケースの別の回避策を投稿することにしました。

私は同じ問題を抱えていて、3 つの Cookie を受け取りましたが、次の Web リクエストから送信されたものとして表示されたのは 2 つだけでした。デバッグを行ったところ、前の回答が示唆するように、エラーはドメイン自体ではないことがわかりました。私の場合、問題は、返され、後続のリクエストで再利用されなかった 3 番目の Cookie が HTTPS リダイレクトに設定されていたことです。、そして「セキュア」プロパティがtrueに設定されていました。したがって、次のリクエスト URL を http://.... から https://.... に変更するだけで、すべての Cookie が送信され、すべてが機能しました。

それが誰かを助けることを願っています!

于 2014-09-29T19:42:18.873 に答える