32

ここで何が悪いのか理解するのに苦労しています。ログイン情報を送信しています。ヘッダーに正しい値のSet-Cookieが表示されていますが、Cookiesコレクションがいっぱいになりません。

これはHTTPS、ログインの自動リダイレクトですが、この問題のトラブルシューティングを試みるために、AllowAutoRedirect=falseで無効にしました。

このスクリーンショットでは、デバッグ情報とCookieが設定されていることを簡単に確認できます。httpWebRequest.Cookieを新しいCookieCollectionに設定しています。

右クリックして[画像を表示]を選択すると、フルサイズで表示されます。

HttpWebRequest httpRequest;
CookieContainer reqCookies = new CookieContainer();
string url = "https://example.com";
string[] email = user.Split('@');
email[0] = System.Web.HttpUtility.UrlEncode(email[0]);
user = email[0] + "@" + email[1];
pass = System.Web.HttpUtility.UrlEncode(pass);

string postData = "email=" + user + "&password=" + pass;
byte[] byteData = Encoding.UTF8.GetBytes(postData);

httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.Referer = url;
httpRequest.CookieContainer = reqCookies;
httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1003.1 Safari/535.19";
httpRequest.Accept = "text/html, application/xhtml+xml, */*";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.ContentLength = byteData.Length;
using (Stream postStream = httpRequest.GetRequestStream())
{
    postStream.Write(byteData, 0, byteData.Length);
    postStream.Close();
}

httpRequest.AllowAutoRedirect = false;
HttpWebResponse b = (HttpWebResponse)httpRequest.GetResponse();

http://www.yahoo.comに接続するのとまったく同じコードを試してみたところ、Cookieが私のコレクションに入れられました...ああ...

Set-Cookieヘッダーの値は次のとおりです。

s = 541E2101-B768-45C8-B814-34A00525E50F; Domain = example.com; パス=/; バージョン=1

4

7 に答える 7

21

5年後の更新では、誰かが実際にそれを行う正しい方法について言及しました。そもそもCookieContainerを正しく設定し、すべてを処理できるようにすることです。さらに下のサムの解決策を参照してください。

C#ASP.NETアプリによって作成されたC#のCookieを読み取るときにも、この問題が見つかりました...;)

それが関係しているかどうかはわかりませんが、私の場合に設定されている2つのCookieは、Cookieのペイロードがコンマで区切られた単一のSet-Cookieヘッダーに書き込まれていることがわかりました。そこで、AppDeveloperのソリューションを適応させて、この複数のCookieの問題に対処し、コメントで言及した名前/値を修正しました。

private static void fixCookies(HttpWebRequest request, HttpWebResponse response) 
{
    for (int i = 0; i < response.Headers.Count; i++)
    {
        string name = response.Headers.GetKey(i);
        if (name != "Set-Cookie")
            continue;
        string value = response.Headers.Get(i);
        foreach (var singleCookie in value.Split(','))
        {
            Match match = Regex.Match(singleCookie, "(.+?)=(.+?);");
            if (match.Captures.Count == 0)
                continue;
            response.Cookies.Add(
                new Cookie(
                    match.Groups[1].ToString(), 
                    match.Groups[2].ToString(), 
                    "/", 
                    request.Host.Split(':')[0]));
        }
    }
}
于 2013-08-04T12:21:08.460 に答える
17

にが設定されていない限り、Cookiesプロパティはnullになります。したがって、これを行う適切な方法は、応答を取得する前にメンバーを設定することです。CookieContainerHttpWebRequestCookieContainer

var request = (HttpWebRequest)HttpWebRequest.Create(..);
request.CookieContainer = new CookieContainer();

var response = request.GetResponse();
// ..response.Cookies will now contain the cookies sent back by the server.

手動で解析する必要はありませんSet-Cookie

詳細については、ドキュメントを参照してください。

于 2018-07-06T03:47:56.513 に答える
15

Webサイトから送信されたヘッダーの形式が正しくないようSet-Cookieです(通常の形式ではないはずです)。

このような場合、Cookieを手動で解析し、それをに解析する必要がありますCookieContainer

for (int i = 0; i < b.Headers.Count; i++)
{
    string name = b.Headers.GetKey(i);
    string value = b.Headers.Get(i);
    if (name == "Set-Cookie")
    {
        Match match = Regex.Match(value, "(.+?)=(.+?);");
        if (match.Captures.Count > 0)
        {
            reqCookies.Add(new Cookie(match.Groups[1].Value, match.Groups[2].Value, "/", "example.com"));
        }
    }
}
于 2013-02-27T03:17:55.700 に答える
7

この回答CookieContainerのようにを使用します。これらの正規表現のアプローチを私につまずかせたのは、のコンマでした。expires=Tue, ...

于 2014-11-19T19:59:17.123 に答える
5

他の回答を見ると、誤ったCookieの処理が改善されました。これらの回答とは異なり、これはすべてのCookieプロパティ(期限切れ、安全など)を自動的に処理し、すべての範囲のCookieで機能します(誤ったCookieが複数ある場合でも)。

これは拡張メソッドとして実装され、次のように使用できます。

//...
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                request.FixCookies(response);
//...

FixCookies()拡張方法:

using System;
using System.Collections.Generic;
using System.Net;

namespace AG.WebHelpers
{
    static public class ExtensionMethods
    {
        static public void FixCookies(this HttpWebRequest request, HttpWebResponse response)
        {
            for (int i = 0; i < response.Headers.Count; i++)
            {
                string name = response.Headers.GetKey(i);
                if (name != "Set-Cookie")
                    continue;
                string value = response.Headers.Get(i);
                var cookieCollection = ParseCookieString(value, () => request.Host.Split(':')[0]);
                response.Cookies.Add(cookieCollection);
            }
        }

        static private CookieCollection ParseCookieString(string cookieString, Func<string> getCookieDomainIfItIsMissingInCookie)
        {
            bool secure = false;
            bool httpOnly = false;

            string domainFromCookie = null;
            string path = null;
            string expiresString = null;

            Dictionary<string, string> cookiesValues = new Dictionary<string, string>();

            var cookieValuePairsStrings = cookieString.Split(';');
            foreach(string cookieValuePairString in cookieValuePairsStrings)
            {
                var pairArr = cookieValuePairString.Split('=');
                int pairArrLength = pairArr.Length;
                for (int i = 0; i < pairArrLength; i++)
                {
                    pairArr[i] = pairArr[i].Trim();
                }
                string propertyName = pairArr[0];
                if (pairArrLength == 1)
                {
                    if (propertyName.Equals("httponly", StringComparison.OrdinalIgnoreCase))
                        httpOnly = true;
                    else if (propertyName.Equals("secure", StringComparison.OrdinalIgnoreCase))
                        secure = true;
                    else
                        throw new InvalidOperationException(string.Format("Unknown cookie property \"{0}\". All cookie is \"{1}\"", propertyName, cookieString));
                    continue;
                }

                string propertyValue = pairArr[1];
                if (propertyName.Equals("expires", StringComparison.OrdinalIgnoreCase))
                    expiresString = propertyValue;
                else if (propertyName.Equals("domain", StringComparison.OrdinalIgnoreCase))
                    domainFromCookie = propertyValue;
                else if (propertyName.Equals("path", StringComparison.OrdinalIgnoreCase))
                    path = propertyValue;
                else
                    cookiesValues.Add(propertyName, propertyValue);
            }

            DateTime expiresDateTime;
            if (expiresString != null)
            {
                expiresDateTime = DateTime.Parse(expiresString);
            }
            else
            {
                expiresDateTime = DateTime.MinValue;
            }
            if (string.IsNullOrEmpty(domainFromCookie))
            {
                domainFromCookie = getCookieDomainIfItIsMissingInCookie();
            }

            CookieCollection cookieCollection = new CookieCollection();
            foreach (var pair in cookiesValues)
            {
                Cookie cookie = new Cookie(pair.Key, pair.Value, path, domainFromCookie);
                cookie.Secure = secure;
                cookie.HttpOnly = httpOnly;
                cookie.Expires = expiresDateTime;

                cookieCollection.Add(cookie);
            }
            return cookieCollection;
        }
    }
}
于 2015-10-04T23:43:39.393 に答える
1

少し遅れるかもしれませんが、関数SetCookiesを使用できます

var cHeader = responce.Headers.Get("Set-Cookie");
var cookie = new CookieContainer();
cookie.SetCookies(new Uri("[...]"), cHeader);
于 2016-06-11T12:54:40.100 に答える
0

この質問は古いことは知っていますが、「Set-Cookie」ヘッダーを適切に解析するコードに出くわしました。カンマで区切られたCookieを処理し、各Cookieの名前、有効期限、パス、値、およびドメインを抽出します。

このコードは、Microsoft独自のCookieパーサーよりもうまく機能します。これは、実際には、公式のCookieパーサーが実行する必要があることです。これは非常に一般的な問題であるため、Microsoftがこれをまだ修正していない理由はわかりません。

元のコードは次のとおりです: 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)
            {
                strPNameAndPValue = strEachCookParts[j];
                if (strPNameAndPValue != string.Empty)
                {
                    NameValuePairTemp = strPNameAndPValue.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;
}
于 2014-02-28T14:39:18.743 に答える