ฉันจะจับ 404 ได้อย่างไร


95

ฉันมีรหัสต่อไปนี้:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "HEAD";
request.Credentials = MyCredentialCache;

try
{
    request.GetResponse();
}
catch
{
}

ฉันจะตรวจจับข้อผิดพลาด 404 ที่เฉพาะเจาะจงได้อย่างไร WebExceptionStatus.ProtocolError สามารถตรวจพบได้เฉพาะข้อผิดพลาดที่เกิดขึ้น แต่ไม่ได้ระบุรหัสที่แน่นอนของข้อผิดพลาด

ตัวอย่างเช่น:

catch (WebException ex)
{
    if (ex.Status != WebExceptionStatus.ProtocolError)
    {
        throw ex;
    }
}

มีประโยชน์ไม่เพียงพอ ... ข้อยกเว้นโปรโตคอลอาจเป็น 401, 503, 403 อะไรก็ได้จริงๆ


13
NNNOOOOOOOOOOOOO! อย่าจับSystem.Exceptionและอย่าขึ้นอยู่กับข้อความยกเว้นในตัวจัดการของคุณ!
Aaronaught

2
คำตอบของ John Saunders นั้นสมบูรณ์แบบที่สุด ฉันคิดว่าคนเพิ่งโหวตเขาออกไป
Aaronaught

3
อย่าใช้throw exคุณจะสร้างข้อยกเว้นใหม่โดยมี call stack ว่างเปล่า เพียงแค่ใช้throw.
krbnr

1
ฉันพบว่าสิ่งนี้ทำให้ตัวเองหงุดหงิดเสมอ ไม่ควรเกิดข้อยกเว้นหากคุณได้รับการตอบสนองที่มีรูปแบบดีและข้อความแสดงข้อผิดพลาดของโปรโตคอลนั้นมีรูปแบบที่ดี ชั้นเรียนควรอนุญาตให้ผู้ใช้ตีความผลลัพธ์และดำเนินการตามนั้น
Jeremy Holovacs

ข้อยกเว้นของ @JeremyHolovacs จะไม่ถูกส่งไปยังสิ่งต่างๆเช่น 404 ในไคลเอนต์ http รุ่นใหม่อีกต่อไป "อย่าใช้ข้อยกเว้นสำหรับขั้นตอนการควบคุม" ดูเหมือนจะไม่รอดทีมผู้สร้างWebRequest
Matt Kocaj

คำตอบ:


115

ใช้HttpStatusCode EnumerationโดยเฉพาะHttpStatusCode.NotFound

สิ่งที่ต้องการ:

HttpWebResponse errorResponse = we.Response as HttpWebResponse;
if (errorResponse.StatusCode == HttpStatusCode.NotFound) {
  //
}

ที่ไหนเป็น
weWebException


ฉันจะเอา NUMBER ออกจากวัตถุโดยไม่สร้างรายการค้นหาของตัวเองได้หรือไม่ ฉันต้องการบางอย่างเช่น int httpresponsecode = HttpStatusCode ToInt () หรือคล้ายกันดังนั้นฉันจึงได้รับ 404
BerggreenDK

2
@BerggreenDK คุณควรจะทำได้เพียงแค่ int httpresonsecode = (int) HttpStatusCode.NotFound
Trev

8
-1 คำอธิบายบางส่วนของ downvote โบราณของฉัน: รหัสพ่น NullReferenceException ถ้าด้วยเหตุผลบางอย่างไม่ได้we.Response ถ้ารหัสความประสงค์ที่จะคิดว่ามันจะมีประเภทนั้นแล้วมันก็ควรโยน:HttpWebResponse HttpWebResponse errorResponse = (HttpWebResponse)we.Response;นี้จะโยนอย่างชัดเจนถ้าเป็นไปไม่ได้ที่เกิดขึ้นแทนลึกลับInvalidCastException NullReferenceException
John Saunders

ฉันAn object reference is required for the non-static field, method, or property 'WebException.Response'ใช้รหัสนี้
Jamie

122
try
{
    var request = WebRequest.Create(uri);
    using (var response = request.GetResponse())
    {
        using (var responseStream = response.GetResponseStream())
        {
            // Process the stream
        }
    }
}
catch (WebException ex)
{
    if (ex.Status == WebExceptionStatus.ProtocolError &&
        ex.Response != null)
    {
        var resp = (HttpWebResponse) ex.Response;
        if (resp.StatusCode == HttpStatusCode.NotFound)
        {
            // Do something
        }
        else
        {
            // Do something else
        }
    }
    else
    {
        // Do something else
    }
}

10
lol @ เป็นตำรวจที่เปิดเผยได้และให้ -1 ทุกคนเพื่อไม่ให้การตอบสนองในบล็อกโดยใช้
รวย

2
มันเป็นงานที่ยาก แต่ต้องมีคนทำ OTOH ฉันแทบไม่ได้เพิ่มคำตอบนี้เลยเพราะมันอาจดูเหมือนว่าฉันกำลังหลอกล่อคนอื่นให้เป็นคำตอบยอดนิยมของฉัน
John Saunders

3
ที่จริงผม upvoted แต่ผมเพิ่งสังเกตเห็นสิ่งหนึ่งที่: อาจมีควรจะเป็นthrow(rethrow) ในตอนท้ายของคุณcatchมิฉะนั้นนี้จะเป็นเพียงแค่เงียบกินชนิดอื่น ๆ WebExceptionของ
Aaronaught

@ จอห์นแซนเดอร์ส: ทำไมคุณไม่ใช้ตามคำขอของคุณด้วย?
Joel Etherton

1
@Joel: ไม่ใช้WebRequest IDisposable
John Saunders

25

ใน C # 6 คุณสามารถใช้ฟิลเตอร์ข้อยกเว้น

try
{
    var request = WebRequest.Create(uri);
    using (var response = request.GetResponse())
    using (var responseStream = response.GetResponseStream())
    {
        // Process the stream
    }
}
catch(WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
{
    // handle 404 exceptions
}
catch (WebException ex)
{
    // handle other web exceptions
}

คุณสมบัติที่ยอดเยี่ยมที่ฉันเคยมองเห็น! ฉันพยายามหาวิธีที่จะจับเพียง 401 ในขณะที่ปล่อยให้คนอื่นผ่านไปยังตัวจัดการข้อยกเว้นทั่วไป นี่คือวิธีที่จะไป!
Lionet Chen

โดดเด่นนี่ควรเป็นคำตอบที่ได้รับการยอมรับ
Lucas925

12

ฉันยังไม่ได้ทดสอบ แต่ควรใช้งานได้

try
{
    // TODO: Make request.
}
catch (WebException ex)
{
    if (ex.Status == WebExceptionStatus.ProtocolError) {
        HttpWebResponse resp = ex.Response as HttpWebResponse;
        if (resp != null && resp.StatusCode == HttpStatusCode.NotFound)
        {
            // TODO: Handle 404 error.
        }
        else
            throw;
    }
    else
        throw;
}

@John Saunders - ฉันกำลังปรับรหัสของ OP ไม่ใช่ปรับให้เหมาะสม
MiffTheFox

@ จอห์น - และบางทีฉันอาจจะแค่คาดหวังให้พวกเขาคัดลอก / วางcatchบล็อกเนื่องจากฉันมีรหัสเดียวกันในการลองเป็น OP คุณควรจะตอบคำถามนี้ไปพร้อมกันเพราะรหัสของ OP
MiffTheFox

1
@ จอห์นเราลืมนี่คือโค้ดตัวอย่าง นี่เป็นอีกวิธีหนึ่งสำหรับ 404 ไม่ใช่วิธีใช้ GetResponse -1 ดูเหมือนจะรุนแรงเล็กน้อย +1 ถึง Miff สำหรับการตอบคำถาม
David Basarab

@ จอห์นฉันคิดว่ามันเป็นการดีที่คุณชี้ให้เห็นในความคิดเห็น วิธีที่ฉันดูการลงคะแนนคือถ้ารหัสที่ให้มาไม่สามารถแก้ปัญหาได้ ขอขอบคุณที่ลบการโหวตลง
David Basarab

@ จอห์น - สบายดีฉันได้กำจัดทุกอย่างแล้ว แต่ตอนนี้มีความสุขไหม?
MiffTheFox

4

ฉันคิดว่าถ้าคุณจับWebExceptionมีข้อมูลบางอย่างที่คุณสามารถใช้เพื่อตรวจสอบว่าเป็น 404 หรือไม่นั่นเป็นวิธีเดียวที่ฉันรู้ในขณะนี้ ... ฉันสนใจที่จะรู้จักคนอื่น ๆ ...

catch(WebException e) {
    if(e.Status == WebExceptionStatus.ProtocolError) {
        var statusCode = (HttpWebResponse)e.Response).StatusCode);
        var description = (HttpWebResponse)e.Response).StatusDescription);
    }
}

2

ลองดู snipit นี้ GetResponse จะส่ง WebRequestException จับสิ่งนั้นและคุณจะได้รับรหัสสถานะจากการตอบกลับ

try {
   // Create a web request for an invalid site. Substitute the "invalid site" strong in the Create call with a invalid name.
     HttpWebRequest myHttpWebRequest = (HttpWebRequest) WebRequest.Create("invalid site");

    // Get the associated response for the above request.
     HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
    myHttpWebResponse.Close();
}
catch(WebException e) {
    Console.WriteLine("This program is expected to throw WebException on successful run."+
                        "\n\nException Message :" + e.Message);
    if(e.Status == WebExceptionStatus.ProtocolError) {
        Console.WriteLine("Status Code : {0}", ((HttpWebResponse)e.Response).StatusCode);
        Console.WriteLine("Status Description : {0}", ((HttpWebResponse)e.Response).StatusDescription);
    }
}
catch(Exception e) {
    Console.WriteLine(e.Message);
}

สิ่งนี้มาจากhttp://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx


2

จับประเภทข้อยกเว้นที่เหมาะสมWebException:

try
{
    var request = (HttpWebRequest) WebRequest.Create(String.Format("http://www.gravatar.com/avatar/{0}?d=404", hashe));

    using(var response = (HttpWebResponse)request.GetResponse())
        Response.Write("has avatar");
}
catch(WebException e) 
{
  if(e.Response.StatusCode == 404) 
    Response.Write("No avatar");
}

@ จอห์นแซนเดอร์สฉันไม่ได้ถกเถียงกับคุณที่นั่น แต่นั่นไม่ใช่คำถามเขาถามวิธีที่ดีที่สุดในการจับ 404 การเปลี่ยนแปลงรหัสของฉันถูก จำกัด ไว้ที่การตอบคำถามเพื่อให้การเปลี่ยนแปลงง่ายและชัดเจนพอ ๆ เป็นไปได้.
Nick Craver

@ จอห์นแซนเดอร์ส: คงที่ฉันคิดว่า "ถ้านี่มีประสิทธิภาพมากที่สุด" จะทำให้คำถามนี้ใช้ได้
Nick Craver

เพิ่งมีการโยนe.Responseเป็นก่อนที่จะดึงดูดการเข้าถึงHttpWebResponse StatusCode
Lankymart

2

ดูที่MSDNเกี่ยวกับสถานะของการตอบกลับ:

...
catch(WebException e) {
  Console.WriteLine("The following error occured : {0}",e.Status);  
}
...

2
@ John Saunders - ฉันยินดีเป็นอย่างยิ่งที่จะส่งต่อไปยัง MSDN (ที่ฉันคัดลอกตัวอย่างมาจาก ... ) วัตถุประสงค์ของรหัสนี้คือเพื่อแสดงการใช้งาน StatusCode ไม่ให้มีประสิทธิภาพมากที่สุด
Dror

2
@ จอห์นแซนเดอร์ - ฉันเหลือ แต่ส่วนที่ฉันต้องการแสดงเพียงเพื่อคุณ :-)
Dror

2

สำหรับผู้คน VB.NET ที่เรียกดูสิ่งนี้ฉันเชื่อว่าเราสามารถจับข้อยกเว้นได้ก็ต่อเมื่อมันเป็น 404 เท่านั้นสิ่งที่ต้องการ:

Try
    httpWebrequest.GetResponse()
Catch we As WebException When we.Response IsNot Nothing _
                              AndAlso TypeOf we.Response Is HttpWebResponse _
                              AndAlso (DirectCast(we.Response, HttpWebResponse).StatusCode = HttpStatusCode.NotFound)

    ' ...

End Try

1

เมื่อ POST หรือ GET ข้อมูลไปยังเซิร์ฟเวอร์โดยใช้คลาส WebRequest ประเภทของข้อยกเว้นจะเป็น WebException ด้านล่างนี้เป็นรหัสสำหรับไฟล์ที่ไม่พบข้อยกเว้น

        //Create a web request with the specified URL
            string path = @"http://localhost/test.xml1";
            WebRequest myWebRequest = WebRequest.Create(path);

       //Senda a web request and wait for response.
                try
                {
                    WebResponse objwebResponse = myWebRequest.GetResponse();
                    Stream stream= objwebResponse.GetResponseStream();

                }
                catch (WebException ex) {
                    if (((HttpWebResponse)(ex.Response)).StatusCode == HttpStatusCode.NotFound) {
                        throw new FileNotFoundException(ex.Message);
                    }

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