Как получить код статуса от веб-клиента?

76

Я использую класс WebClient для публикации некоторых данных в веб-форме. Я хотел бы получить код статуса ответа формы. До сих пор я узнал, как получить код состояния, если есть исключение

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

Теги:
webclient

10 ответов

20
Лучший ответ

Пробовал. ResponseHeaders не включают код состояния.

Если я не ошибаюсь, WebClient способен абстрагировать несколько разных запросов в одном вызове метода (например, правильно обрабатывать 100 ответов, перенаправлений и т.п.). Я подозреваю, что без использования HttpWebRequest и HttpWebResponse отдельный код состояния может быть недоступен.

Мне приходит в голову, что если вы не заинтересованы в промежуточных кодах состояния, вы можете спокойно предположить, что окончательный код состояния находится в диапазоне 2xx (успешный), в противном случае вызов не будет успешным.

Код состояния, к сожалению, отсутствует в словаре ResponseHeaders.

  • 2
    кажется, что единственным способом будет веб-запрос / ответ
  • 1
    Кажется проблемой, если вы явно ищете какое-то другое сообщение серии 200 (например, 201 CREATED - см. W3.org/Protocols/rfc2616/rfc2616-sec10.html ). : / / Было бы хорошо, если бы это было явно доступно, даже если "промежуточные" были пропущены.
Показать ещё 2 комментария
77

Вы можете проверить, является ли ошибка типа 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..
}
  • 0
    Большое спасибо за этот ответ, который указывает на правильный способ получения заголовков ответов - из WebException, а не из WebClient.ResponseHeaders.
  • 1
    да, лучший подход на самом деле - прочитать данные ответа в блоке try catch и перехватить WebException
Показать ещё 4 комментария
27

Если вы используете .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;
  • 0
    Не работает на Windows Phone - GetWebResponse () существует только в двухпараметрическом варианте. Еще +1.
  • 0
    Интересно, что это не работает. Рад, что ваш ответ делает свое дело!
Показать ещё 1 комментарий
27

Есть способ сделать это, используя отражение. Он работает с .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, который не позволяет получить доступ к закрытым членам даже через отражение
  • 1
    Также работает на .NET 4.5.
Показать ещё 3 комментария
8

Ответ Эрика не работает на 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!");
}
  • 2
    За это проголосовали почему? ФП четко заявляет: However if the form is submitted successfully and no exception is thrown...
1

Это то, что я использую для расширения функциональности 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
            }
  • 0
    Это отлично сработало для меня, так как я искал код ответа. Отличное решение!
  • 0
    Имейте в виду, что [в отличие от HttpClient] ответы 4xx и 5xx приводят к исключению WebException в "response = base.GetWebResponse (request);" линия. Вы можете получить статус и ответ из исключения (если они существуют).
Показать ещё 1 комментарий
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()
0

Вы можете использовать вызов "client.ResponseHeaders [..]", см. ссылку для примера возврата материала из ответа

  • 1
    возвращаемые заголовки ответа - это заголовки сервера, такие как сервер, дата, прагма и т. д. но без кода состояния (200,301,404 ...)
  • 1
    К сожалению об этом, был немного удивлен, обнаружив, что не вернулся.
-1

Вы можете попробовать этот код, чтобы получить код состояния HTTP из WebException или из OpenReadCompletedEventArgs.Error. Он также работает в 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;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню