Web istemcisinden durum kodu nasıl alınır?


90

WebClientSınıfı bir web formuna bazı verileri göndermek için kullanıyorum . Form gönderiminin yanıt durum kodunu almak istiyorum. Şimdiye kadar bir istisna varsa durum kodunu nasıl alacağımı öğrendim

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

Ancak, form başarıyla gönderilirse ve herhangi bir istisna atılmazsa, durum kodunu (200,301,302, ...) bilmem

Herhangi bir istisna atılmadığında durum kodunu almanın bir yolu var mı?

Not: httpwebrequest / httpwebresponse kullanmamayı tercih ederim

Yanıtlar:


23

Denedim. ResponseHeaders, durum kodunu içermez.

Yanılmıyorsam, WebClienttek bir yöntem çağrısında birden çok farklı isteği soyutlayabilir (örneğin, 100 Devam yanıtını, yeniden yönlendirmeleri ve benzerlerini doğru şekilde işleme). Ben kullanmadan şüpheli HttpWebRequestve HttpWebResponse, ayrı bir durum kodu mevcut olmayabilir.

Ara durum kodlarıyla ilgilenmiyorsanız, son durum kodunun 2xx (başarılı) aralığında olduğunu güvenle varsayabilirsiniz, aksi takdirde arama başarılı olmaz.

Durum kodu maalesef ResponseHeaderssözlükte yok.


2
tek yol web istemi / yanıt gibi görünüyor
julio

1
Açıkça başka bir 200 serisi mesaj arıyorsanız bir sorun gibi görünür (ör. 201 CREATED - Bkz: w3.org/Protocols/rfc2616/rfc2616-sec10.html ). : - / "Ara" olanlar atlansa bile bu açıkça mevcut olsaydı iyi olurdu.
Norman H

1
@NormanH, katılmıyorum. Durum kodları söz konusu olduğunda WebClient'in biraz sızdıran bir soyutlama olduğu görülüyor. Şerefe!
kbrimington

88

Hatanın türde olup olmadığını kontrol edebilir WebExceptionve ardından yanıt kodunu inceleyebilirsiniz;

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!");
}

veya

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

Yanıt başlıklarını almanın doğru yolunu gösteren bu yanıt için çok teşekkürler - WebClient.ResponseHeaders'dan değil WebException'dan.
Hong

1
evet, en iyi yaklaşım aslında yanıt verilerini bir deneme yakalama bloğunda okumak ve WebException'ı yakalamak
Henrik Hartz

2
Burada bir şey eksik. Ne 'System.Exception' ne de 'System.Net.Exception' 'Hata' için bir tanım içermiyor
Greg Woods

13
Çağrı başarılı olursa istisna olmayacaktır (yani 2xx veya 3xx döndürür). Orijinal poster 3xx arıyordu, 204'ü arıyorum, diğer insanlar 201'i arıyor. Bu sorulan soruya cevap vermiyor.
Simon Brooke

4
Orijinal gönderen şöyle yazdığında bu cevabın şu ana kadar nasıl yükseltildiğinden emin değilim: "Herhangi bir istisna atılmadığında durum kodunu almanın bir yolu var mı?" Sanırım şimdi olumsuz oy kullanmanın bir anlamı yok.
Frog Pr1nce

33

Bunu yansıma kullanarak yapmanın bir yolu var. .NET 4.0 ile çalışır. Özel bir alana erişir ve değişiklik yapılmadan .NET'in diğer sürümlerinde çalışmayabilir.

Microsoft'un bu alanı neden bir özellikle ifşa etmediği hakkında hiçbir fikrim yok.

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, bu, yansıma yoluyla bile özel üyelere erişime izin vermeyen Windows Phone'da mümkün değil
Brendan

BindingFlags için "using System.Reflection;"
dlchambers

Güzel, ama SubStatusCode almanın bir yolu var mı? Örneğin 403.1 veya 403.2?
Roni Tovi

Yanıt nesnesinin bir SubStatusCode özelliği vardır. msdn.microsoft.com/en-us/library/…
Dmitry S.

30

.Net 4.0 (veya daha az) kullanıyorsanız:

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 veya daha yenisini kullanıyorsanız, HttpClient'e geçin :

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

Windows Phone'da çalışmıyor - GetWebResponse () yalnızca iki parametreli yapıda mevcuttur. Hala +1.
Seva Alekseyev


Daha yüksek cevaplardaki yansımanın olmadığı benim için çalıştı (.NET 4.5 windows 7 ve 10 uygulaması)
David Shields

9

Erik'in cevabı Windows Phone'da olduğu gibi çalışmıyor. Aşağıdakiler yapar:

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;
        }
    }
}

En azından kullanırken işe yarar OpenReadAsync; diğer xxxAsyncyöntemler için dikkatli testler şiddetle tavsiye edilir. Çerçeve GetWebResponse'yi kod yolu boyunca bir yere çağırır; tek yapması gereken yanıt nesnesini yakalamak ve önbelleğe almaktır.

Yedek kod bu kod parçacığında 200'dür, çünkü gerçek HTTP hataları - 500, 404 vb. - yine de istisna olarak rapor edilir. Bu numaranın amacı, benim özel durumumda (304) (Değiştirilmedi) hata içermeyen kodları yakalamaktır. Dolayısıyla, geri dönüş, durum kodunun bir şekilde mevcut olmaması durumunda, en azından hatalı olmadığını varsayar.


3

Kullanmalısın

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

3
Bu neden oylandı? OP açıkça şunu belirtir: However if the form is submitted successfully and no exception is thrown...
Kenneth K.

2

WebClient işlevselliğini genişletmek için kullandığım şey bu. StatusCode ve StatusDescription her zaman en son yanıt kodunu / açıklamasını içerecektir.

                /// <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; }
                }

Böylece bir gönderi yapabilir ve şu yolla sonuç alabilirsiniz:

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

Yanıt kodunu ararken bu benim için harika çalıştı. Güzel çözüm!
evilfish

[HttpClient'ten farklı olarak] 4xx ve 5xx yanıtlarının "response = base.GetWebResponse (istek)" de bir WebException oluşmasına neden olduğunu unutmayın; hat. Durum ve yanıtı istisnadan alabilirsiniz (varsa).
mwardm

Evet. Yine de normal gibi istisnaları yakalamalısınız. Ancak, bir istisna yoksa, bu OP'nin ne istediğini ortaya çıkarır.
DFTR

1

Sadece başka birinin yukarıda açıklanan hack'in F # sürümüne ihtiyaç duyması durumunda.

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 [..]" çağrısını kullanabilmeniz gerekir , yanıttan geri dönüş örnekleri için bu bağlantıya bakın


1
döndürülen yanıt başlıkları sunucu, tarih, pragma vb. gibi sunucu başlıklarıdır. ancak durum kodu yok (200,301,404 ...)
julio

1
Bunun için üzgünüm, bunun iade edilmediğini görünce biraz şaşırdım.
Paul Hadfield

-1

HTTP durum kodunu WebException'dan veya OpenReadCompletedEventArgs.Error'dan almak için bu kodu deneyebilirsiniz. Silverlight'ta da çalışır çünkü SL'de WebExceptionStatus.ProtocolError tanımlı değildir.

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.