จะรับรหัสสถานะจากเว็บไคลเอนต์ได้อย่างไร?


90

ฉันใช้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

คำตอบ:


23

พยายามแล้ว ResponseHeaders ไม่มีรหัสสถานะ

หากฉันไม่เข้าใจผิดWebClientก็สามารถแยกคำขอที่แตกต่างกันออกไปได้หลายรายการในการเรียกวิธีการเดียว (เช่นจัดการ 100 คำตอบต่อการเปลี่ยนเส้นทางและอื่น ๆ ที่คล้ายกันอย่างถูกต้อง) ฉันสงสัยว่าหากไม่ใช้HttpWebRequestและHttpWebResponseรหัสสถานะที่แตกต่างกันอาจไม่สามารถใช้ได้

สำหรับฉันแล้วถ้าคุณไม่สนใจรหัสสถานะระดับกลางคุณสามารถถือว่ารหัสสถานะสุดท้ายอยู่ในช่วง 2xx (สำเร็จ) ได้อย่างปลอดภัยมิฉะนั้นการโทรจะไม่สำเร็จ

ขออภัยไม่มีรหัสสถานะอยู่ในResponseHeadersพจนานุกรม


2
ดูเหมือนว่าวิธีเดียวคือการร้องขอเว็บ / การตอบกลับ
Julio

1
ดูเหมือนจะเป็นปัญหาหากคุณกำลังมองหาข้อความ 200 ชุดอื่น ๆ อย่างชัดเจน (เช่น 201 CREATED - ดู: w3.org/Protocols/rfc2616/rfc2616-sec10.html ) : - / จะเป็นการดีหากสามารถใช้งานได้อย่างชัดเจนแม้ว่าจะข้ามรายการ "ระดับกลาง" ไปแล้วก็ตาม
Norman H

1
@ NormanH ฉันไม่เห็นด้วย ดูเหมือนว่า WebClient จะเป็นนามธรรมที่รั่วไหลเล็กน้อยเมื่อพูดถึงรหัสสถานะ ไชโย!
kbrimington

88

คุณสามารถตรวจสอบว่าข้อผิดพลาดเป็นประเภท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..
}

ขอบคุณมากสำหรับคำตอบนี้ซึ่งชี้ให้ฉันเห็นวิธีที่ถูกต้องในการรับส่วนหัวการตอบกลับ - จาก WebException ไม่ใช่จาก WebClient.ResponseHeaders
Hong

1
ใช่วิธีที่ดีที่สุดคือการอ่านข้อมูลการตอบสนองในบล็อก try catch และจับ WebException
Henrik Hartz

2
ฉันขาดอะไรบางอย่างที่นี่ ทั้ง 'System.Exception' หรือ 'System.Net.Exception' ไม่มีคำจำกัดความสำหรับ 'Error'
Greg Woods

13
จะไม่มีข้อยกเว้นหากการโทรสำเร็จ (เช่นส่งคืน 2xx หรือ 3xx) ผู้โพสต์ต้นฉบับกำลังมองหา 3xx ฉันกำลังมองหา 204 คนอื่นกำลังมองหา 201 สิ่งนี้ไม่ตอบคำถามที่ถาม
ไซมอนบรูค

4
ไม่แน่ใจว่าคำตอบนี้ได้รับการโหวตอย่างไรเมื่อผู้โพสต์ต้นฉบับเขียนว่า: "มีวิธีรับรหัสสถานะเมื่อไม่มีข้อยกเว้นหรือไม่" ฉันเดาว่าไม่มีประเด็นในการลงคะแนนตอนนี้
กบพ.

33

มีวิธีทำโดยใช้การสะท้อนแสง ใช้งานได้กับ. 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 ซึ่งไม่อนุญาตให้เข้าถึงสมาชิกส่วนตัวแม้จะผ่านการไตร่ตรองก็ตาม
Brendan

โปรดทราบว่า BindingFlags ต้องการ "การใช้ System.Reflection;"
dlchambers

ดี แต่มีวิธีรับ SubStatusCode หรือไม่ ตัวอย่างเช่น 403.1 หรือ 403.2?
Roni Tovi

วัตถุตอบสนองมีคุณสมบัติ SubStatusCode msdn.microsoft.com/en-us/library/…
Dmitry S.

30

หากคุณกำลังใช้. 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;

ไม่ทำงานบน Windows Phone - GetWebResponse () มีอยู่ในรสชาติแบบสองพารามิเตอร์เท่านั้น ยังคง +1
Seva Alekseyev


ทำงานให้ฉันโดยที่การไตร่ตรองในคำตอบที่สูงกว่าไม่ได้ (แอพ. NET 4.5 windows 7 และ 10)
David Shields

9

คำตอบของ 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 (ไม่ได้แก้ไข) ดังนั้นทางเลือกจะถือว่าหากรหัสสถานะไม่สามารถใช้งานได้อย่างน้อยก็เป็นรหัสที่ไม่ผิดพลาด


3

คุณควรใช้

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

3
นี่ได้รับการโหวตว่าทำไม? OP ระบุอย่างชัดเจน: However if the form is submitted successfully and no exception is thrown...
Kenneth K.

2

นี่คือสิ่งที่ฉันใช้เพื่อขยายการทำงานของ 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
            }

สิ่งนี้ได้ผลดีสำหรับฉันเพราะฉันกำลังมองหารหัสตอบกลับ ทางออกที่ดี!
evilfish

โปรดทราบว่า [ไม่เหมือนกับการตอบกลับ HttpClient] 4xx และ 5xx ส่งผลให้ WebException ถูกส่งไปที่ "response = base.GetWebResponse (request);" ไลน์. คุณสามารถดึงสถานะและการตอบกลับจากข้อยกเว้น (หากมี)
mwardm

ใช่. คุณยังต้องจับข้อยกเว้นเหมือนปกติ อย่างไรก็ตามหากไม่มีข้อยกเว้นสิ่งนี้จะเปิดเผยสิ่งที่ OP ต้องการ
DFTR

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()

-1

คุณควรจะสามารถใช้การเรียก "client.ResponseHeaders [.. ]" ได้โปรดดูลิงก์นี้เพื่อดูตัวอย่างการรับสิ่งของคืนจากการตอบกลับ


1
ส่วนหัวการตอบกลับที่ส่งคืนคือส่วนหัวของเซิร์ฟเวอร์เช่นเซิร์ฟเวอร์วันที่ pragma เป็นต้น แต่ไม่มีรหัสสถานะ (200,301,404 ... )
Julio

1
ขออภัยด้วยแปลกใจเล็กน้อยที่ไม่ได้ส่งคืน
Paul Hadfield

-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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.