Bagaimana cara mendapatkan kode status dari klien web?

90

Saya menggunakan WebClientkelas untuk mengirim beberapa data ke formulir web. Saya ingin mendapatkan kode status tanggapan dari pengiriman formulir. Sejauh ini saya telah menemukan cara mendapatkan kode status jika ada pengecualian

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

Namun jika formulir berhasil dikirim dan tidak ada pengecualian yang dibuang maka saya tidak akan tahu kode statusnya (200.301.302, ...)

Apakah ada cara untuk mendapatkan kode status ketika tidak ada pengecualian?

NB: Saya memilih untuk tidak menggunakan httpwebrequest / httpwebresponse

julio
sumber

Jawaban:

23

Sudah mencobanya. ResponseHeaders tidak menyertakan kode status.

Jika saya tidak salah, WebClientmampu mengabstraksi beberapa permintaan berbeda dalam satu panggilan metode (mis. Menangani 100 tanggapan Lanjutkan, pengalihan, dan sejenisnya dengan benar). Saya menduga bahwa tanpa menggunakan HttpWebRequestdanHttpWebResponse , kode status yang berbeda mungkin tidak tersedia.

Terpikir oleh saya bahwa, jika Anda tidak tertarik dengan kode status perantara, Anda dapat dengan aman mengasumsikan kode status terakhir dalam kisaran 2xx (berhasil), jika tidak, panggilan tidak akan berhasil.

Kode status sayangnya tidak ada dalam ResponseHeaderskamus.

kbrimington.dll
sumber
2
tampaknya satu-satunya cara adalah webrequest / response
julio
1
Tampaknya menjadi masalah jika Anda secara eksplisit mencari 200 pesan seri lainnya (yaitu 201 CREATED - Lihat: w3.org/Protocols/rfc2616/rfc2616-sec10.html ). : - / Alangkah baiknya jika itu tersedia secara eksplisit bahkan jika yang "perantara" dilewati.
Norman H
1
@NormanH, saya tidak setuju. Tampaknya WebClient adalah abstraksi yang bocor dalam hal kode status. Bersulang!
kbrimington
87

Anda dapat memeriksa apakah kesalahan tersebut bertipe WebExceptiondan kemudian memeriksa kode respons;

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

atau

try
{
    // send request
}
catch (WebException e)
{
    // check e.Status as above etc..
}
Henrik Hartz
sumber
Terima kasih banyak atas jawaban ini yang mengarahkan saya ke cara yang benar untuk mendapatkan header respons - dari WebException, bukan dari WebClient.ResponseHeaders.
Hong
1
ya, pendekatan terbaik sebenarnya adalah membaca data respons di blok coba tangkap dan menangkap WebException
Henrik Hartz
2
Saya melewatkan sesuatu di sini. Baik 'System.Exception' atau 'System.Net.Exception' berisi definisi untuk 'Error'
Greg Woods
13
Tidak akan ada pengecualian jika panggilan berhasil (yaitu mengembalikan 2xx atau 3xx). Poster asli mencari 3xx, saya mencari 204, orang lain mencari 201. Ini tidak menjawab pertanyaan yang diajukan.
Simon Brooke
4
Tidak yakin bagaimana jawaban ini mendapat suara positif sejauh ini ketika poster asli menulis: "Adakah cara untuk mendapatkan kode status ketika tidak ada pengecualian?" Saya kira tidak ada gunanya downvoting sekarang.
Frog Pr1nce
33

Ada cara untuk melakukannya dengan refleksi. Ia bekerja dengan .NET 4.0. Itu mengakses bidang pribadi dan mungkin tidak bekerja di versi .NET tanpa modifikasi.

Saya tidak tahu mengapa Microsoft tidak mengekspos bidang ini dengan properti.

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;
}
Dmitry S.
sumber
2
FWIW, ini tidak mungkin pada Windows Phone yang tidak mengizinkan akses anggota pribadi bahkan melalui refleksi
Brendan
Perhatikan bahwa BindingFlags membutuhkan "using System.Reflection;"
dlchambers
Bagus, tetapi apakah ada cara untuk mendapatkan SubStatusCode? Misalnya 403.1 atau 403.2?
Roni Tovi
Objek respons memiliki properti SubStatusCode. msdn.microsoft.com/en-us/library/…
Dmitry S.
30

Jika Anda menggunakan .Net 4.0 (atau kurang):

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

Jika Anda menggunakan .Net 4.5.X atau yang lebih baru, beralihlah ke HttpClient :

var response = await client.GetAsync("http://www.contoso.com/");
var statusCode = response.StatusCode;
Erik Philips
sumber
Tidak berfungsi di Windows Phone - GetWebResponse () hanya ada dalam rasa dua parameter. Masih +1.
Seva Alekseyev
Menarik bahwa itu tidak berhasil. Senang jawaban Anda berhasil!
Erik Philips
Berhasil untuk saya, di mana refleksi dalam jawaban yang lebih tinggi tidak (.NET 4.5 windows 7 dan 10 app)
David Shields
9

Jawaban Erik tidak berfungsi di Windows Phone sebagaimana adanya. Yang berikut ini:

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

Setidaknya itu terjadi saat menggunakan OpenReadAsync; untuk yang lainxxxAsync metode , pengujian yang cermat akan sangat disarankan. Kerangka kerja memanggil GetWebResponse di suatu tempat di sepanjang jalur kode; yang perlu dilakukan hanyalah menangkap dan menyimpan objek respons ke dalam cache.

Kode fallback adalah 200 dalam cuplikan ini karena kesalahan HTTP asli - 500, 404, dll - tetap dilaporkan sebagai pengecualian. Tujuan dari trik ini adalah untuk menangkap kode non-kesalahan, dalam kasus khusus saya 304 (Tidak diubah). Jadi fallback mengasumsikan bahwa jika kode status entah bagaimana tidak tersedia, setidaknya kode itu tidak salah.

Seva Alekseyev
sumber
3

Kamu harus menggunakan

if (e.Status == WebExceptionStatus.ProtocolError)
{
   HttpWebResponse response = (HttpWebResponse)ex.Response;             
   if (response.StatusCode == HttpStatusCode.NotFound)
      System.Diagnostics.Debug.WriteLine("Not found!");
}
LeMoussel
sumber
3
Ini dipilih mengapa? OP dengan jelas menyatakan: However if the form is submitted successfully and no exception is thrown...
Kenneth K.
2

Inilah yang saya gunakan untuk memperluas fungsionalitas WebClient. StatusCode dan StatusDescription akan selalu berisi kode / deskripsi respons terbaru.

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

Dengan demikian Anda dapat melakukan posting dan mendapatkan hasilnya melalui:

            byte[] response = null;
            using (WebClientCert client = new WebClientCert())
            {
                response = client.UploadValues(postUri, PostFields);
                HttpStatusCode code = client.StatusCode;
                string description = client.StatusDescription;
                //Use this information
            }
DFTR
sumber
Ini bekerja dengan baik untuk saya karena saya sedang mencari kode respons. Solusi bagus!
evilfish
Ketahuilah bahwa [tidak seperti HttpClient] respons 4xx dan 5xx menghasilkan WebException yang dilemparkan ke "response = base.GetWebResponse (request);" garis. Anda dapat menarik status dan respons dari pengecualian (jika ada).
mwardm
Iya. Anda masih harus menangkap pengecualian seperti biasa. Akan tetapi, jika tidak ada pengecualian, ini menunjukkan apa yang diinginkan OP.
DFTR
1

Untuk berjaga-jaga jika orang lain membutuhkan versi F # dari peretasan yang dijelaskan di atas.

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()
jpe
sumber
-1

Anda seharusnya dapat menggunakan panggilan "client.ResponseHeaders [..]", lihat tautan ini untuk contoh mendapatkan barang kembali dari tanggapan

Paul Hadfield
sumber
1
header respons yang dikembalikan adalah header server seperti server, tanggal, pragma, dll. tetapi tidak ada kode status (200,301,404 ...)
julio
1
Maaf tentang itu, sedikit terkejut menemukan itu tidak dikembalikan.
Paul Hadfield
-1

Anda dapat mencoba kode ini untuk mendapatkan kode status HTTP dari WebException atau dari OpenReadCompletedEventArgs.Error. Ia bekerja di Silverlight juga karena SL tidak memiliki WebExceptionStatus.ProtocolError yang ditentukan.

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