C# 如何从webclient获取状态代码?

C# 如何从webclient获取状态代码?,c#,.net,vb.net,webclient,C#,.net,Vb.net,Webclient,我正在使用WebClient类将一些数据发布到web表单。我想获取表单提交的响应状态代码。到目前为止,我已经了解了如何在出现异常时获取状态代码 Catch wex As WebException If TypeOf wex.Response Is HttpWebResponse Then msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode) End If 但是,如果表

我正在使用
WebClient
类将一些数据发布到web表单。我想获取表单提交的响应状态代码。到目前为止,我已经了解了如何在出现异常时获取状态代码

Catch wex As WebException
        If TypeOf wex.Response Is HttpWebResponse Then
          msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode)
            End If
但是,如果表单提交成功并且没有引发异常,那么我将不知道状态代码(200301302,…)

当没有抛出异常时,是否有方法获取状态代码


PS:我不喜欢使用httpwebrequest/httpwebresponse,我试过了。负责人不包括状态代码

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

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


不幸的是,状态代码没有出现在
ResponseHeaders
字典中。

您应该能够使用“client.ResponseHeaders[…]”调用,有关从响应中取回内容的示例,请参见此

有一种使用反射的方法。它适用于.NET4.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;
}
如果您使用的是.Net 4.0(或更低版本):

如果您使用的是.Net 4.5.X或更高版本,请切换到:


您可以检查错误类型是否为
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!");
}

你应该使用

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

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(未修改)中。因此,回退假设,如果状态代码不知何故不可用,至少不会出错。

您可以尝试使用此代码从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;
}

以防其他人需要上述黑客的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()
开放系统
开放系统
开放系统.Net
类型WebClientEx()=
继承WebClient()
[]val可变m_响应:WebResponse
覆盖x.GetWebResponse(请求:WebRequest)=

x、 m_Resp HttpWebRequest)。AllowAutoRedirect这是我用来扩展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; }
                }


返回的响应头是服务器头,如服务器、日期、pragma等。但是没有状态代码(200301404…)。对此感到抱歉,我有点惊讶地发现没有返回。如果您明确查找其他200系列消息(即201已创建-请参阅:),那么webrequest/ResponseEMS似乎是唯一的方法. :-/ 即使跳过了“中间”部分,如果能显式使用,那就太好了。@NormanH,我不反对。当涉及到状态代码时,WebClient似乎有点泄漏抽象。干杯非常感谢您的回答,它为我指出了获取响应头的正确方法-从WebException,而不是从WebClient.ResponseHeaders。是的,最好的方法实际上是在try-catch块中读取响应数据并捕获WebException。我这里遗漏了一些内容。“System.Exception”或“System.Net.Exception”均未包含“Error”的定义。如果调用成功,则不会出现异常(即返回2xx或3xx)。原来的海报是3xx,我在找204,其他人在找201。这并没有回答所问的问题。我不确定这个答案到目前为止是如何得到提升的,因为原始海报写道:“在没有引发异常的情况下,是否有某种方法可以获取状态代码?”我想现在没有必要进行下推表决。在Windows Phone上不起作用-GetWebResponse()只存在于两种参数化风格中。仍然+1。有趣的是它不起作用。对我来说很有用,在更高答案中的反射没有(.NET 4.5 windows 7和10 app)FWIW,这在windows Phone上是不可能的,因为windows Phone不允许通过反射访问私人成员注意BindingFlags要求“使用System.reflection;”不错,但是有办法获取子状态代码吗?例如403.1或403.2?响应对象具有SubStatusCode属性。这是为什么?OP明确指出:
但是如果表单提交成功并且没有引发异常…
这对我来说非常有效,因为我正在寻找响应代码。很好的解决方案!请注意,[与HttpClient不同]4xx和5xx响应会导致在“response=base.GetWebResponse(request);”行引发WebException。您可以从异常中提取状态和响应(如果存在)。是。您仍然必须像正常情况一样捕获异常。但是,如果没有异常,这将暴露OP想要的内容。
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;
}
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()
                /// <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
            }