如何从webclient获取状态代码?


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

Answers:


23

试了一下。ResponseHeader不包含状态码。

如果我没记错的话,WebClient能够在一个方法调用中抽象出多个不同的请求(例如,正确处理100个Continue响应,重定向等)。我怀疑如果不使用HttpWebRequestHttpWebResponse,则可能无法使用不同的状态代码。

在我看来,如果您对中间状态代码不感兴趣,则可以安全地假定最终状态代码在2xx(成功)范围内,否则,调用将不会成功。

不幸的是,ResponseHeaders词典中没有状态码。


2
看来唯一的办法就是webrequest / response
julio 2010年

1
如果您明确地在寻找其他200系列消息(即201已创建-请参阅: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..
}

非常感谢这个答案,这为我指出了从WebException而不是WebClient.ResponseHeaders获取响应标头的正确方法。

1
是的,最好的方法实际上是在try catch块中读取响应数据并捕获WebException
Henrik Hartz

2
我在这里想念东西。无论是“System.Exception的”或“System.Net.Exception”包含了“错误”的定义
格雷格·伍兹

13
如果调用成功(即返回2xx或3xx),也不例外。原始海报正在寻找3xx,我正在寻找204,其他人正在寻找201。这没有回答所问的问题。
西蒙·布鲁克

4
最初的发帖人说:“当没有抛出异常时,是否有某种方法可以获取状态代码?我想现在投票毫无意义。
Frog Pr1nce

33

有一种使用反射的方法。它适用于.NET 4.0。它访问私有字段,并且未经修改可能无法在其他版本的.NET中使用。

我不知道为什么Microsoft不使用属性公开此字段。

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上是不可能的,即使通过反射也不允许访问私有成员
Brendan

请注意,BindingFlags需要“使用System.Reflection;”。
dlchambers,2015年

很好,但是有没有办法获取SubStatusCode?例如403.1或403.2?
罗尼·托维

响应对象具有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()仅以两参数形式存在。仍然+1。
Seva Alekseyev

有趣的是,它不起作用。 很高兴您的回答可以解决问题!
Erik Philips

为我工作,在更高的答案中没有反映(.NET 4.5 Windows 7和10应用程序)
大卫·希尔兹

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。所有需要做的就是捕获并缓存响应对象。

此代码段中的后备代码为200,因为无论如何,真正的HTTP错误(500、404等)都被报告为异常。此技巧的目的是捕获非错误代码,在我的特定情况下为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...
Kenneth 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 '17

请注意,[与HttpClient不同] 4xx和5xx响应会导致在“ response = base.GetWebResponse(request);”处引发WebException。线。您可以从异常中提取状态和响应(如果存在)。
mwardm '18

是。您仍然必须像平常一样捕获异常。但是,如果没有例外,这将揭示OP的要求。
DFTR

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

您可以尝试使用此代码从WebException或OpenReadCompletedEventArgs.Error获取HTTP状态代码。它也可以在Silverlight中使用,因为SL没有定义WebExceptionStatus.ProtocolError。

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.