Làm cách nào để lấy mã trạng thái từ webclient?


90

Tôi đang sử dụng WebClientlớp học để đăng một số dữ liệu lên biểu mẫu web. Tôi muốn nhận mã trạng thái phản hồi của việc gửi biểu mẫu. Cho đến nay, tôi đã tìm ra cách lấy mã trạng thái nếu có ngoại lệ

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

Tuy nhiên, nếu biểu mẫu được gửi thành công và không có ngoại lệ nào được ném ra thì tôi sẽ không biết mã trạng thái (200,301,302, ...)

Có cách nào để lấy mã trạng thái khi không có ngoại lệ nào được ném ra không?

Tái bút: Tôi không muốn sử dụng httpwebrequest / httpwebresponse

Câu trả lời:


23

Đã thử nó ra. ResponseHeaders không bao gồm mã trạng thái.

Nếu tôi không nhầm, WebClientcó khả năng trừu tượng hóa nhiều yêu cầu riêng biệt trong một lệnh gọi phương thức (ví dụ: xử lý chính xác 100 phản hồi Tiếp tục, chuyển hướng và những thứ tương tự). Tôi nghi ngờ rằng nếu không sử dụng HttpWebRequestHttpWebResponse, mã trạng thái riêng biệt có thể không có sẵn.

Tôi xảy ra với tôi rằng, nếu bạn không quan tâm đến mã trạng thái trung gian, bạn có thể an toàn cho rằng mã trạng thái cuối cùng nằm trong phạm vi 2xx (thành công), nếu không, cuộc gọi sẽ không thành công.

Rất tiếc, mã trạng thái không có trong ResponseHeaderstừ điển.


2
có vẻ như cách duy nhất sẽ là webrequest / phản hồi
julio

1
Có vẻ sự cố nếu bạn đang tìm kiếm một số thông báo loạt 200 khác (tức là 201 ĐÃ ĐƯỢC TẠO - Xem: w3.org/Protocols/rfc2616/rfc2616-sec10.html ). : - / Sẽ rất tuyệt nếu điều đó rõ ràng có sẵn ngay cả khi những cái "trung gian" bị bỏ qua.
Norman H

1
@NormanH, tôi không đồng ý. Có vẻ như WebClient có một chút trừu tượng khi nói đến mã trạng thái. Chúc mừng!
kbrimington

87

Bạn có thể kiểm tra xem lỗi thuộc loại nào WebExceptionvà sau đó kiểm tra mã phản hồi;

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

hoặc là

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

Cảm ơn rất nhiều vì câu trả lời này đã chỉ cho tôi cách thích hợp để nhận tiêu đề phản hồi - từ WebException, không phải từ WebClient.ResponseHeaders.
Hồng

1
yeah, phương pháp tốt nhất là thực sự để đọc dữ liệu phản ứng trong một khối try catch và bắt WebException
Henrik Hartz

2
Tôi đang thiếu một cái gì đó ở đây. Cả 'System.Exception' hoặc 'System.Net.Exception' đều không chứa định nghĩa cho 'Error'
Greg Woods

13
Sẽ không có ngoại lệ nếu cuộc gọi thành công (tức là trả về 2xx hoặc 3xx). Người đăng ban đầu đang tìm kiếm 3xx, tôi đang tìm 204, những người khác đang tìm 201. Điều này không trả lời câu hỏi được hỏi.
Simon Brooke

4
Không chắc câu trả lời này đã được ủng hộ như thế nào cho đến nay khi người đăng ban đầu viết: "Có cách nào đó để lấy mã trạng thái khi không có ngoại lệ nào được ném ra không?" Tôi đoán không có điểm nào để từ chối bây giờ.
Frog Pr1nce

33

Có một cách để làm điều đó bằng cách sử dụng phản xạ. Nó hoạt động với .NET 4.0. Nó truy cập vào một trường riêng tư và có thể không hoạt động trong các phiên bản .NET khác nếu không có sửa đổi.

Tôi không biết tại sao Microsoft không hiển thị trường này với một thuộc tính.

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, điều này không thể thực hiện được trên Windows Phone không cho phép truy cập các thành viên riêng tư ngay cả khi phản ánh
Brendan

Lưu ý rằng BindingFlags yêu cầu "using System.Reflection;"
dlchambers

Tốt, nhưng có cách nào để lấy SubStatusCode không? Ví dụ 403.1 hoặc 403.2?
Roni Tovi

Đối tượng phản hồi có thuộc tính SubStatusCode. msdn.microsoft.com/en-us/library/…
Dmitry S.

29

Nếu bạn đang sử dụng .Net 4.0 (hoặc ít hơn):

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

Nếu bạn đang sử dụng .Net 4.5.X hoặc mới hơn, hãy chuyển sang HttpClient :

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

Không hoạt động trên Windows Phone - GetWebResponse () chỉ tồn tại ở dạng hai tham số. Vẫn là +1.
Seva Alekseyev


Làm việc cho tôi, trong đó phản ánh trong các câu trả lời cao hơn không (ứng dụng .NET 4.5 windows 7 và 10)
David Shields

9

Câu trả lời của Erik không hoạt động trên Windows Phone. Những điều sau đây:

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

Ít nhất nó làm khi sử dụng OpenReadAsync; cho người khácxxxAsync phương pháp , nên thử nghiệm cẩn thận. Khuôn khổ gọi GetWebResponse ở đâu đó dọc theo đường dẫn mã; tất cả những gì cần làm là chụp và lưu vào bộ nhớ cache đối tượng phản hồi.

Mã dự phòng là 200 trong đoạn mã này vì lỗi HTTP chính hãng - 500, 404, v.v. - vẫn được báo cáo là ngoại lệ. Mục đích của thủ thuật này là để nắm bắt các mã không lỗi, trong trường hợp cụ thể của tôi là 304 (Không được sửa đổi). Vì vậy, dự phòng giả định rằng nếu mã trạng thái bằng cách nào đó không khả dụng, thì ít nhất nó cũng là một mã không sai.


3

Bạn nên sử dụng

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

3
Điều này đã được bình chọn tại sao? OP ghi rõ: However if the form is submitted successfully and no exception is thrown...
Kenneth K.

2

Đây là những gì tôi sử dụng để mở rộng chức năng WebClient. StatusCode và StatusDescription sẽ luôn chứa mã / mô tả phản hồi gần đây nhất.

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

Vì vậy, bạn có thể thực hiện một bài viết và nhận được kết quả thông qua:

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

Điều này làm việc tuyệt vời cho tôi khi tôi đang tìm kiếm mã phản hồi. Giải pháp tốt!
evilfish

Lưu ý rằng [không giống như với HttpClient] các phản hồi 4xx và 5xx dẫn đến một WebException được ném vào "response = base.GetWebResponse (request);" hàng. Bạn có thể lấy trạng thái và phản hồi từ ngoại lệ (nếu chúng tồn tại).
mwardm

Đúng. Bạn vẫn phải bắt các ngoại lệ giống như bình thường. Tuy nhiên, nếu không có ngoại lệ, điều này làm lộ những gì OP muốn.
DFTR

1

Đề phòng trường hợp người khác cần phiên bản F # của bản hack được mô tả ở trên.

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

Bạn sẽ có thể sử dụng lệnh gọi "client.ResponseHeaders [..]", hãy xem liên kết này để biết các ví dụ về cách lấy lại nội dung từ phản hồi


1
các tiêu đề phản hồi được trả về là các tiêu đề máy chủ như máy chủ, ngày tháng, pragma, v.v. nhưng không có mã trạng thái (200,301,404 ...)
julio

1
Xin lỗi về điều đó, hơi ngạc nhiên khi thấy rằng nó đã không được trả lại.
Paul Hadfield

-1

Bạn có thể thử mã này để lấy mã trạng thái HTTP từ WebException hoặc từ OpenReadCompletedEventArgs.Error. Nó cũng hoạt động trong Silverlight vì SL không có WebExceptionStatus.ProtocolError được xác định.

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.