none
HTTPでのリダイレクト前のヘッダーの取得あるいはリダイレクト先のURLの所得がわかりません。 RRS feed

  • 質問

  •  リダイレクト前のヘッダーが取得できません。「//ヘッダーの表示。」では、リダイレクトが終了した段階のヘッダーが表示されます。
     リダイレクト先URLの取得にはねWebClientのGetWebResponse()をoverrideして使用するといいとのことでしたが、どのように記述したらいいかわかりません。
     また、下記リストではコメントアウトしてありますが、GetWebResponse()の使用は、「アクセスできない保護レベルになっています。」エラーが出てコンパイルできません。

            private void button1_Click(object sender, EventArgs e)
            {
                richTextBox1.Clear();

                String uristr = textBox1.Text; ;
                String headerstr = textBox2.Text;

                WebClient wc = new WebClient();

                byte[] headerdata = Encoding.UTF8.GetBytes(headerstr);

                NameValueCollection myQStrCollection = new NameValueCollection();
                myQStrCollection.Add("u", textBox3.Text);
                wc.QueryString = myQStrCollection;


                byte[] responsedata = wc.UploadData(uristr, "POST", headerdata);


                richTextBox1.Text = Encoding.ASCII.GetString(responsedata);
                richTextBox1.AppendText("\n\nCount = " + wc.ResponseHeaders.Count.ToString() + "\n");
                for (int ii = 0; ii < wc.ResponseHeaders.Count; ii++)
                {
                    richTextBox1.AppendText(wc.ResponseHeaders.GetKey(ii) + " = " + wc.ResponseHeaders.Get(ii) + "\n");//ヘッダーの表示。
                }

    /*
                WebRequest wrq = WebRequest.Create(uristr);

                WebResponse wrsp = wc.GetWebResponse(wrq);

                richTextBox1.AppendText("\n\n" + wrsp.ResponseUri.ToString() + "\n");
    */
            }

     

    2007年10月1日 15:57

すべての返信

  • 確か、WebClient を使わず、WebRequest を直接使えばいけたかな。

    WebRequest.Create を使って HTTP URL で作成した WebRequest は、HttpWebRequest にキャストでき、

    HttpWebRequest の AllowAutoRedirect プロパティを false にすると、3xx 系レスポンスを参照することができます。

    リダイレクト先のURL は、Location ヘッダを参照すれば良いはずです。

     

    コード ブロック

    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(...);

    req.AllowAutoRedirect = false;

    // ヘッダやメソッド等設定

    HttpWebResponse res = (HttpWebResponse)req.GetResponse();

    // res.StatusCode を確認

    // Location やその他ヘッダを確認

    2007年10月30日 2:47
  • リダイレクト先URLの取得にはねWebClientのGetWebResponse()をoverrideして使用するといいとのことでしたが、どのように記述したらいいかわかりません。

     kes@ さんからの引用

    確か、WebClient を使わず、WebRequest を直接使えばいけたかな。

     

    WebClientは内部でWebRequestを使っています。WebRequestだけを直接使っても可能ですが、

    WebClient内部でWebRequestをごにょることで可能です。

     

    WebClientを継承したクラスを作成し、GetWebRequest、GetWebResponseを実装します。

    特殊な用途ではクラス内部でWebRequest/WebResponseを作成し、返しても良いですが、

    普通は以下のように親に作らせたオブジェクトを加工します。

     

    コード ブロック

    Protected Overrides Function GetWebRequest(ByVal address As Uri) As WebRequest

      Dim request As WebRequest = MyBase.GetWebRequest(address)

      request.XXXX = XXXX

      ...

      request.YYYY = YYYY

      return request

    End Function

     

     

    あとはkesさんの言うように、AllowAutoRedirectをFalseにすれば、

    WebRequestが自動でリダイレクトしなくなり、

    Locationヘッダにリダイレクト先が格納されます。

     

    それだけですと、リダイレクトされた際にGetWebResponseは例外を吐きますので、

    UploadDataなどのメソッドも例外を吐くことになります。

    例外を拾って自動でリダイレクトする為のコードをGetWebResponse内に書くか、

    WebClient外部に例外をきちんと拾い再送するコードを書かなければいけません。

     

    蛇足になりますが、

    UploadDataではLocationヘッダーが届きますが、

    DownloadFileなどでは、対象が移動している場合でもContent-Locationヘッダーを用いて、

    リダイレクトせずにダウンロードされるサーバーもあります。

    (この振舞いがRFCでは推奨されています。)

    ですので、リダイレクトに対応した汎用のWebClientを作る場合には

    Content-LocationヘッダとLocationヘッダを両方処理しなければいけません。

    2007年10月30日 9:06
  •  れい さんからの引用

    リダイレクトされた際にGetWebResponseは例外を吐きますので、

    UploadDataなどのメソッドも例外を吐くことになります。



    3xx ステータスは例外になりませんよ。
    AllowAutoRedirect = false ではリダイレクト処理が自動的に行われないだけで、
    成功(2xx ステータス等)と同じような扱いになります。

    リダイレクトかどうかを判断するためには、ステータスコードの確認が確実ですが、
    WebClient ではステータスコードの確認ができないので、
    Location ヘッダの存在などで判断することになると思います。

    厳密さが必要であれば、WebClient 派生クラスで更に (Http)WebResponse を操作するか、
    (Http)WebRequest を直接使って書くことになるかと思います。
    それぞれに長所短所がありますので、使いやすい方をお選びになってはいかがですか。
    2007年10月30日 11:20
  • 3xx ステータスは例外になりませんよ。
    AllowAutoRedirect = false ではリダイレクト処理が自動的に行われないだけで、
    成功(2xx ステータス等)と同じような扱いになります。

     

    おおっと。これは失礼しました。

    おっしゃるとおり、3xxでは、基本的に例外は投げられませんでした。

     

    ただ、いくつか例外があります。

    例えば、事前認証がオフの時にサーバーに認証を要求され、且つリダイレクトされるべきURLをリクエストした場合に、

    例外が投げられる場合があります。

    この場合、サーバーは3xxを返していても、WebRequestのStatusCodeは4xxのエラーになります。

    WebRequest/Responseは非常にめんどくさくて、

    サーバーの種類、認証の種類、認証要求とリダイレクトの順序、URLがフォルダなのかファイルなのか、

    DAV実装があるのか無いのか、といった条件でだいぶ振舞いが変わります。

    サーバーが3xxを返すときに例外が投げられることはない、

    と思って実装することはできないようです。

     

    リダイレクトかどうかを判断するためには、ステータスコードの確認が確実ですが、
    WebClient ではステータスコードの確認ができないので、
    Location ヘッダの存在などで判断することになると思います。

    WebClientそのものではWebRequest.AllowAutoRedirectがいじれないので、

    WebClientを使うなら、派生クラスでGetWebRequest/GetWebResponseを実装せざるを得ないわけで、

    それならGetWebResponse内でStatusCodeを見て判断すれば良いように思います。

     

    Locationヘッダーを見て判断するなら、

    リダイレクト以外で使用される場合があるのでその点には注意が必要です。

    (PUTの時など。)

     

    私の今までの経験だと、

    WebRequestですらなかなかうまく動かないので、

    WebClientを使ってごにょごにょするのは更に大変だと思います。

    とくにファイルアップロードは。

     

    リダイレクト前のヘッダーが必要、というのがそもそも不思議なのですが。

    2007年10月30日 12:38
  •  「リダイレクト前のヘッダーが取得できません。」というのは、初めのクライアントからサーバーへの要求に対する、サーバーからクライアントへの(3xx系のリダイレクト)応答HEADERのLocationヘッダーの内容を取得したかったので、書いたものです。3xx系レスポンスを参照したいのに、それができないんです、という意味で書きました。3xx系レスポンスがクライアントに届くと、クライアントは直ちにLocationヘッダーに記されているところへとアクセス、つまり、自動でリダイレクト先へアクセス、してしまって、3xx系レスポンスのヘッダーを参照するチャンスが存在せず、「リダイレクト前のヘッダーが取得できません。」ということです。
     自分としては、「リダイレクト先のURLの取得」が目当てでして、WebClientを使わず、HttpWebRequestとHttpWebResponseを使用して、3xx系のレスポンスのヘッダーのLocationヘッダーを参照するのではなく、HttpWebResponseのResponseUriを参照することで、「リダイレクト先のURLの取得」を果たしました。この方法は、リダイレクトが1回だけで、リダイレクト応答とリダイレクトアクセスが連発しない場合にしか有効ではないのだとは思いますが。

                HttpWebRequest hwrq = (HttpWebRequest)WebRequest.Create("https://ドメイン名/パス名");
                hwrq.KeepAlive = false;
                hwrq.ProtocolVersion = HttpVersion.Version10;
                hwrq.Method = "POST";
                string postData = "pd=XXXXXXXXX";
                ASCIIEncoding encoding = new ASCIIEncoding();
                byte[] byte1 = encoding.GetBytes(postData);
                hwrq.ContentType = "application/x-www-form-urlencoded";
                hwrq.ContentLength = byte1.Length;
                Stream newStream = hwrq.GetRequestStream();
                newStream.Write(byte1, 0, byte1.Length);//POSTの実施。
                newStream.Close();

                HttpWebResponse hwrs = (HttpWebResponse)hwrq.GetResponse();
                richTextBox1.AppendText("\nredirecturi = "+hwrs.ResponseUri.ToString()+"\n");
                                //上行、リダイレクト先を表示。

     

    2007年11月3日 16:02
  • 解決したならいいのですが。

     


     自分としては、「リダイレクト先のURLの取得」が目当てでして、

    ならそう書いたらもっと早く解決したでしょうね。

    MSDNにも載ってますし。

     

    と思ったら、件名にしっかりと「あるいはリダイレクト先のURLの所得」とありましたね。

    よく読まねばいけませんでした。

     


    この方法は、リダイレクトが1回だけで、リダイレクト応答とリダイレクトアクセスが連発しない場合にしか有効ではないのだとは思いますが。

     

    そんなことはありません。

    ResponseUriは実際に応答したURIを返します。

    認証があるとちょっと動作が複雑になりますが、HttpWebRequestは複数回のリダイレクトに対応しています。

    MaximumAutomaticRedirectionsで最大数を設定できます。

    http://msdn2.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect.aspx

    2007年11月4日 7:15