Webクライアントからステータスコードを取得する方法


90

WebClientクラスを使用して、データをWebフォームに投稿しています。フォーム送信の応答ステータスコードを取得したいのですが。これまでのところ、例外がある場合にステータスコードを取得する方法を見つけました

Catch wex As WebException
        If TypeOf wex.Response Is HttpWebResponse Then
          msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode)
            End If

ただし、フォームが正常に送信され、例外がスローされない場合、ステータスコード(200,301,302、...)がわかりません。

例外がスローされないときにステータスコードを取得する方法はありますか?

PS:私はhttpwebrequest / httpwebresponseを使用したくない

回答:


23

試してみました。ResponseHeadersにはステータスコードは含まれません。

私が間違っていなければWebClient、1つのメソッド呼び出しで複数の異なる要求を抽象化することができます(たとえば、100のContinue応答、リダイレクトなどを正しく処理する)。とを使用しないHttpWebRequestHttpWebResponse、個別のステータスコードが利用できない可能性があります。

中間ステータスコードに関心がない場合は、最終ステータスコードが2xx(成功)の範囲にあると安全に想定できます。それ以外の場合、呼び出しは成功しません。

残念ながら、ステータスコードはResponseHeaders辞書に存在しません。


2
唯一の方法はwebrequest / responseのようです
julio

1
他の200シリーズのメッセージを明示的に探している場合は問題があるようです(例:201 CREATED-参照:w3.org/Protocols/rfc2616/rfc2616-sec10.html)。:-/「中間」のものがスキップされたとしても、それが明示的に利用可能であるとよいでしょう。
ノーマンH

1
@NormanH、私は反対しません。ステータスコードに関しては、WebClientは少し漏れやすい抽象概念のように思えます。乾杯!
kbrimington

87

エラーの種類WebExceptionを確認してから、応答コードを調べることができます。

if (e.Error.GetType().Name == "WebException")
{
   WebException we = (WebException)e.Error;
   HttpWebResponse response = (System.Net.HttpWebResponse)we.Response;
   if (response.StatusCode==HttpStatusCode.NotFound)
      System.Diagnostics.Debug.WriteLine("Not found!");
}

または

try
{
    // send request
}
catch (WebException e)
{
    // check e.Status as above etc..
}

WebClient.ResponseHeadersではなくWebExceptionから-応答ヘッダーを取得する正しい方法を私に示してくれたこの回答に感謝します。
香港

1
ええ、最善の方法は、実際にはtry catchブロックで応答データを読み取り、WebExceptionをキャッチすることです
Henrik Hartz

2
ここに何か欠けています。'System.Exception'も 'System.Net.Exception'も 'Error'の定義を含みません
Greg Woods

13
呼び出しが成功した(つまり、2xxまたは3xxを返す)場合でも例外はありません。元のポスターは3xxを探していました。私は204を探しています。他の人は201を探しています。これは、質問の回答にはなりません。
Simon Brooke

4
元の投稿者が「例外がスローされないときにステータスコードを取得する方法はありますか?」と書いたとき、この回答がどのように支持されたかはわかりません。今は反対投票しても意味がないと思います。
カエルPr1nce

33

リフレクションを使用してそれを行う方法があります。.NET 4.0で動作します。プライベートフィールドにアクセスし、変更を加えないと、他のバージョンの.NETでは機能しない場合があります。

マイクロソフトがこのフィールドをプロパティで公開しなかった理由がわかりません。

private static int GetStatusCode(WebClient client, out string statusDescription)
{
    FieldInfo responseField = client.GetType().GetField("m_WebResponse", BindingFlags.Instance | BindingFlags.NonPublic);

    if (responseField != null)
    {
        HttpWebResponse response = responseField.GetValue(client) as HttpWebResponse;

        if (response != null)
        {
            statusDescription = response.StatusDescription;
            return (int)response.StatusCode;
        }
    }

    statusDescription = null;
    return 0;
}

2
FWIW、これはリフレクションを介してもプライベートメンバーへのアクセスを許可しないWindows Phoneでは不可能です
ブレンダン

BindingFlagsには「System.Reflectionの使用」が必要であることに注意してください。
dlchambers

いいですが、SubStatusCodeを取得する方法はありますか?例:403.1または403.2?
Roni Tovi 16

応答オブジェクトにはSubStatusCodeプロパティがあります。msdn.microsoft.com/en-us/library/...
ドミトリーS.

29

.Net 4.0(またはそれ以下)を使用している場合:

class BetterWebClient : WebClient
{
        private WebRequest _Request = null;

        protected override WebRequest GetWebRequest(Uri address)
        {
            this._Request = base.GetWebRequest(address);

            if (this._Request is HttpWebRequest)
            {
                ((HttpWebRequest)this._Request).AllowAutoRedirect = false;
            }

            return this._Request;
        } 

        public HttpStatusCode StatusCode()
        {
            HttpStatusCode result;

            if (this._Request == null)
            {
                throw (new InvalidOperationException("Unable to retrieve the status 
                       code, maybe you haven't made a request yet."));
            }

            HttpWebResponse response = base.GetWebResponse(this._Request) 
                                       as HttpWebResponse;

            if (response != null)
            {
                result = response.StatusCode;
            }
            else
            {
                throw (new InvalidOperationException("Unable to retrieve the status 
                       code, maybe you haven't made a request yet."));
            }

            return result;
        }
    }

.Net 4.5.X以降を使用している場合は、HttpClientに切り替えます

var response = await client.GetAsync("http://www.contoso.com/");
var statusCode = response.StatusCode;

Windows Phoneでは機能しません-GetWebResponse()は2つのパラメーターのフレーバーでのみ存在します。まだ+1。
Seva Alekseyev 2013年

それが機能しないのは興味深いことです。 あなたの答えがうまくいくうれしいです!
Erik Philips

より効果的な答えが反映されない(.NET 4.5 Windows 7および10アプリ)
David Shields

9

Erikの答えは、そのままではWindows Phoneで機能しません。以下は行います:

class WebClientEx : WebClient
{
    private WebResponse m_Resp = null;

    protected override WebResponse GetWebResponse(WebRequest Req, IAsyncResult ar)
    {
        try
        {
            this.m_Resp = base.GetWebResponse(request);
        }
        catch (WebException ex)
        {
            if (this.m_Resp == null)
                this.m_Resp = ex.Response;
        }
        return this.m_Resp;
    }

    public HttpStatusCode StatusCode
    {
        get
        {
            if (m_Resp != null && m_Resp is HttpWebResponse)
                return (m_Resp as HttpWebResponse).StatusCode;
            else
                return HttpStatusCode.OK;
        }
    }
}

少なくともOpenReadAsync; 他のxxxAsync方法については、慎重なテストが強く推奨されます。フレームワークは、コードパスのどこかでGetWebResponseを呼び出します。必要なのは、応答オブジェクトをキャプチャしてキャッシュすることだけです。

いずれにしても、本物のHTTPエラー(500、404など)が例外として報告されるため、このスニペットではフォールバックコードは200です。このトリックの目的は、私の特定のケース304(変更されていない)でエラー以外のコードをキャプチャすることです。したがって、フォールバックは、ステータスコードが何らかの理由で利用できない場合でも、少なくともエラーではないコードであると想定します。


3

あなたは使うべきです

if (e.Status == WebExceptionStatus.ProtocolError)
{
   HttpWebResponse response = (HttpWebResponse)ex.Response;             
   if (response.StatusCode == HttpStatusCode.NotFound)
      System.Diagnostics.Debug.WriteLine("Not found!");
}

3
これはなぜ投票されたのですか?OPは明確に述べて: However if the form is submitted successfully and no exception is thrown...
ケネス・K.

2

これは、WebClient機能を拡張するために使用するものです。StatusCodeおよびStatusDescriptionには、常に最新の応答コード/説明が含まれます。

                /// <summary>
                /// An expanded web client that allows certificate auth and 
                /// the retrieval of status' for successful requests
                /// </summary>
                public class WebClientCert : WebClient
                {
                    private X509Certificate2 _cert;
                    public WebClientCert(X509Certificate2 cert) : base() { _cert = cert; }
                    protected override WebRequest GetWebRequest(Uri address)
                    {
                        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
                        if (_cert != null) { request.ClientCertificates.Add(_cert); }
                        return request;
                    }
                    protected override WebResponse GetWebResponse(WebRequest request)
                    {
                        WebResponse response = null;
                        response = base.GetWebResponse(request);
                        HttpWebResponse baseResponse = response as HttpWebResponse;
                        StatusCode = baseResponse.StatusCode;
                        StatusDescription = baseResponse.StatusDescription;
                        return response;
                    }
                    /// <summary>
                    /// The most recent response statusCode
                    /// </summary>
                    public HttpStatusCode StatusCode { get; set; }
                    /// <summary>
                    /// The most recent response statusDescription
                    /// </summary>
                    public string StatusDescription { get; set; }
                }

したがって、投稿を行って結果を得ることができます:

            byte[] response = null;
            using (WebClientCert client = new WebClientCert())
            {
                response = client.UploadValues(postUri, PostFields);
                HttpStatusCode code = client.StatusCode;
                string description = client.StatusDescription;
                //Use this information
            }

応答コードを探していたので、これは私にとってはうまくいきました。素敵な解決策!
evilfish 2017

[HttpClientとは異なり] 4xxおよび5xx応答は、「response = base.GetWebResponse(request);」でWebExceptionがスローされることに注意してください。ライン。(存在する場合)例外からステータスと応答を取得できます。
mwardm 2018

はい。通常と同じように、例外をキャッチする必要があります。ただし、例外がない場合、これはOPが必要とするものを公開します。
DFTR 2018年

1

誰かが上記のハックのF#バージョンを必要とする場合に備えて。

open System
open System.IO
open System.Net

type WebClientEx() =
     inherit WebClient ()
     [<DefaultValue>] val mutable m_Resp : WebResponse

     override x.GetWebResponse (req: WebRequest ) =
        x.m_Resp <- base.GetWebResponse(req)
        (req :?> HttpWebRequest).AllowAutoRedirect <- false;
        x.m_Resp

     override x.GetWebResponse (req: WebRequest , ar: IAsyncResult  ) =
        x.m_Resp <- base.GetWebResponse(req, ar)
        (req :?> HttpWebRequest).AllowAutoRedirect <- false;
        x.m_Resp

     member x.StatusCode with get() : HttpStatusCode = 
            if not (obj.ReferenceEquals (x.m_Resp, null)) && x.m_Resp.GetType() = typeof<HttpWebResponse> then
                (x.m_Resp :?> HttpWebResponse).StatusCode
            else
                HttpStatusCode.OK

let wc = new WebClientEx()
let st = wc.OpenRead("http://www.stackoverflow.com")
let sr = new StreamReader(st)
let res = sr.ReadToEnd()
wc.StatusCode
sr.Close()
st.Close()

-1

「client.ResponseHeaders [..]」呼び出しを使用できるはずです。応答からデータを取得する例については、このリンクを参照してください


1
返される応答ヘッダーは、server、date、pragmaなどのサーバーヘッダーです。ステータスコードなし(200,301,404 ...)
julio

1
申し訳ありませんが、返却されなかったことに少し驚いていました。
ポールハドフィールド

-1

このコードを試して、WebExceptionまたはOpenReadCompletedEventArgs.ErrorからHTTPステータスコードを取得できます。SLにはWebExceptionStatus.ProtocolErrorが定義されていないため、Silverlightでも機能します。

HttpStatusCode GetHttpStatusCode(System.Exception err)
{
    if (err is WebException)
    {
        WebException we = (WebException)err;
        if (we.Response is HttpWebResponse)
        {
            HttpWebResponse response = (HttpWebResponse)we.Response;
            return response.StatusCode;
        }
    }
    return 0;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.