12

HttpWebRequest/を使用して GET および POST リクエストを行う基本的なクラスがありますHttpWebResponse

クラスを使用して API にログインし、データを要求します。Windows 8 の "Metro" アプリケーションでは、期待どおりに動作します。Windows Phone 8 アプリケーションでは、ログインは成功したように見えますが、その後のデータ要求では Cookie が送信されず、サーバーはクライアントがログインしていないかのように応答します。

クラスは次のとおりです。これとまったく同じコードが Windows 8 アプリと Windows Phone アプリで使用されています。

class Class1
    {
        CookieContainer cookieJar = new CookieContainer();
        CookieCollection responseCookies = new CookieCollection();

        public async Task<string> httpRequest(HttpWebRequest request)
        {
            string received;

            using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
            {
                using (var responseStream = response.GetResponseStream())
                {
                    using (var sr = new StreamReader(responseStream))
                    {
                        cookieJar = request.CookieContainer;
                        responseCookies = response.Cookies;
                        received = await sr.ReadToEndAsync();
                    }
                }
            }

            return received;
        }

        public async Task<string> get(string path)
        {
            var request = WebRequest.Create(new Uri(path)) as HttpWebRequest;
            request.CookieContainer = cookieJar;

            return await httpRequest(request);
        }

        public async Task<string> post(string path, string postdata)
        {
            var request = WebRequest.Create(new Uri(path)) as HttpWebRequest;
            request.Method = "POST";
            request.CookieContainer = cookieJar;

            byte[] data = Encoding.UTF8.GetBytes(postdata);
            using (var requestStream = await Task<Stream>.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, null))
            {
                await requestStream.WriteAsync(data, 0, data.Length);
            }

            return await httpRequest(request);
        }
    }

そして、リクエストを開始するコード:

    var n = new Class1();
    await n.post("https://mydomain.com/api/login/", "username=myusername&password=mypassword");
    await n.get("https://mydomain.com/reader/feeds/");

奇妙なことに、ドメイン名の前に「www.」を付けると、Windows Phone 8 アプリと Windows 8 Metro アプリの両方で機能します。

ドメインの扱い方に関係があると思います。Cookie のドメインは「.mydomain.com」であり、プレフィックスがなければ、Cookie はそのドメインに属していないと見なす必要があります。いくつかの検索の後、誰かが同様の問題に気付いたというレポートを見つけました。

私が理解していないのは、Windows 8 アプリと Windows Phone アプリでこれが異なる方法で処理される理由です。そのため、1 行ごとに同じコードが 1 つのプラットフォームでは機能するが、別のプラットフォームでは失敗します。


私はこれをさらに掘り下げました。

これに使用したサーバー コードは PHP です。

<?php

if ($_REQUEST["what"] == "set")
{
    setcookie("TestCookie",$_REQUEST["username"] . " " . $_REQUEST["password"], time()+3600*24, "/", "subd.mydomain.com");
}

if ($_GET["what"] == "get")
{
    var_dump($_COOKIE);

C# のクライアント コード:

    var n = new ClassLibrary1.Class1();
            await n.get("http://subd.mydomain.com/?what=set&username=foo&password=bar");
            await n.get("http://subd.mydomain.com/?what=get");

サーバーからの Cookie 応答の例を次に示します。

Set-Cookie: ARRAffinity=295612ca; Path=/;Domain=subd.mydomain.com
Set-Cookie: TestCookie=foo+bar; expires=Fri, 04-Jan-2013 17:19:25 GMT; path=/; domain=subd.mydomain.com

Windows 8 Store/Metro アプリでは、これが結果です。

array(2) {
  ["ARRAffinity"]=>
  string(8) "295612ca"
  ["TestCookie"]=>
  string(7) "foo bar"
}

Windows Phone アプリでは、これが結果です。

array(0){
}

このように設定されている場合、Windows Phone は Cookie を認識しません。

の設定方法を変更するTestCookieと、サーバーからの結果は次のようになります。

Set-Cookie: ARRAffinity=295612ca;Path=/;Domain=subd.mydomain.com
Set-Cookie: TestCookie=foo+bar; expires=Fri, 04-Jan-2013 17:29:59 GMT; path=/

TestCookieはドメインを明示的に設定しなくなりました。ARRAffinity は変更されていません。

Windows 8 Store/Metro アプリは、これを返すようになりました:

array(2) {
  ["TestCookie"]=>
  string(7) "foo bar"
  ["ARRAffinity"]=>
  string(8) "295612ca"
}

Windows Phone 8 アプリは、これを返します。

array(1) {
  ["TestCookie"]=>
  string(7) "foo bar"
}

ARRAffinityドメインを明示的に宣言しているため、Cookie は送信されません。

いくつかのブレークポイントを割り当てCookieContainerてリクエストを確認すると、m_domainTable

+       [0] {[.subd.mydomain.com, System.Net.PathList]} System.Collections.Generic.KeyValuePair<string,System.Net.PathList>
+       [1] {[subd.mydomain.com, System.Net.PathList]}  System.Collections.Generic.KeyValuePair<string,System.Net.PathList>

送信されない Cookie は.subd.mydomain.comコンテナー内にあります。これは、Windows 8 と Windows Phone 8 の両方で同じです。

ただし、Cookie が次のように宣言されている場合:

Set-Cookie: TestCookie=foo+bar; expires=Fri, 04-Jan-2013 17:19:25 GMT; path=/; domain=.mydomain.com

Windows Phone 8 では正しく送信されます。

私の最初のケースでは、mydomain.com または www.mydomain.com のどちらからアクセスされたかに関係なく、サーバーは Cookie を同じ方法で宣言します。「.mydomain.com」と同じですが、Windows Phone 8 は「.mydomain.com」の Cookie を「mydomain.com」に送信する必要があるとは考えていないようです。これには問題があります。サーバーが「subd.mydomain.com」をドメインとして設定しても、前にドットがあるものとして扱われ、それ自体の障害がなければ機能しないためです。Cookie を正しく処理するには、ドメイン情報を Cookie と一緒に送信しないようにする必要があるようです。

4

1 に答える 1

7

これは既知の問題です。フィードバックの記事はこちらです。

現在はあまり進行していませんが、比較的最近提出されました。このバグに投票し、定期的にステータスを確認することをお勧めします。待つ余裕がない場合は、Microsoft サポートに連絡して、より迅速なフォローアップを依頼してください。

于 2013-01-10T13:47:15.593 に答える