Làm thế nào tôi có thể bắt được 404?


93

Tôi có mã sau:

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

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

Làm cách nào tôi có thể bắt được lỗi 404 cụ thể? WebExceptionStatus.ProtocolError chỉ có thể phát hiện ra lỗi đã xảy ra, nhưng không cung cấp mã chính xác của lỗi.

Ví dụ:

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

Chỉ là không đủ hữu ích ... ngoại lệ giao thức có thể là 401, 503, 403, bất cứ điều gì thực sự.


13
NNNOOOOOOOOOOOOO! Đừng nắm bắt System.Exceptionvà đừng phụ thuộc vào văn bản ngoại lệ trong trình xử lý của bạn!
Aaronaught

2
Câu trả lời của John Saunders là đầy đủ nhất. Tôi nghĩ rằng mọi người chỉ bất chấp từ chối anh ấy.
Aaronaught

3
Không sử dụng throw ex, bạn sẽ tạo ra một ngoại lệ mới với ngăn xếp cuộc gọi trống. Chỉ cần sử dụng throw.
krbnr

1
Bản thân tôi luôn thấy điều này thật bực bội. Một ngoại lệ sẽ không được đưa ra nếu bạn nhận được phản hồi được định dạng tốt và thông báo lỗi giao thức chắc chắn được tạo đúng. Lớp nên cho phép người dùng diễn giải kết quả và hành động tương ứng.
Jeremy Holovacs

Các ngoại lệ @JeremyHolovacs không còn được ném cho những thứ như 404 trong ứng dụng khách http mới hơn. "Không sử dụng các ngoại lệ cho dòng điều khiển" dường như không tồn tại trong đội ngũ những người xây dựngWebRequest
Matt Kocaj

Câu trả lời:


113

Sử dụng HttpStatusCode Enumeration, cụ thểHttpStatusCode.NotFound

Cái gì đó như:

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

Ở đâu
wea WebException.


Tôi có thể lấy NUMBER ra từ các đối tượng mà không cần lập danh sách tra cứu của riêng mình không? Tôi muốn có một cái gì đó như: int httpresponsecode = HttpStatusCode.ToInt () hoặc tương tự vì vậy tôi có được 404
BerggreenDK

2
@BerggreenDK, bạn sẽ có thể thực hiện int httpresonsecode = (int) HttpStatusCode.NotFound
Trev

7
-1 Giải thích một phần về downvote cổ xưa của tôi: mã ném NullReferenceException nếu, vì một số lý do, we.Responsekhông phải HttpWebResponse. Nếu mã mong muốn rằng nó sẽ luôn luôn có loại đó, sau đó nó chỉ đơn giản nên đúc: HttpWebResponse errorResponse = (HttpWebResponse)we.Response;. Điều này sẽ ném ra một cách rõ ràng InvalidCastExceptionnếu điều không thể xảy ra, thay vì một điều bí ẩn NullReferenceException.
John Saunders

Tôi An object reference is required for the non-static field, method, or property 'WebException.Response'sử dụng mã này.
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 @ là cảnh sát IDisposable và cho mọi người -1 vì không gói phản hồi trong một khối đang sử dụng.
Phong phú

2
Đó là một công việc khó khăn, nhưng phải có người làm. OTOH, tôi gần như không thêm câu trả lời này, vì có vẻ như tôi đang đánh lừa mọi người khác để biến câu trả lời của tôi thành câu trả lời được xếp hạng cao nhất.
John Saunders

3
Tôi thực sự đã ủng hộ, nhưng tôi chỉ nhận thấy một điều: Có lẽ phải có throw(rethrow) ở cuối của bạn catch, nếu không điều này sẽ chỉ âm thầm ăn bất kỳ loại nào khác WebException.
Aaronaught

@John Saunders: Tại sao bạn không có cách sử dụng xung quanh yêu cầu của bạn?
Joel Etherton

1
@Joel: WebRequestkhông thực hiện IDisposable.
John Saunders

23

Trong C # 6, bạn có thể sử dụng các bộ lọc ngoại lệ .

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
}

Một tính năng rất thú vị mà tôi đã bỏ qua! Tôi tiếp tục tìm kiếm các phương pháp để chỉ bắt 401 trong khi để những người khác chuyển qua trình xử lý ngoại lệ chung. Đây là con đường để đi!
Lionet Chen

12

Tôi chưa thử nghiệm cái này, nhưng nó sẽ hoạt động

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 - Tôi đang điều chỉnh mã của OP, không phải tối ưu hóa nó.
MiffTheFox

@John - Và có lẽ tôi chỉ mong họ sao chép / dán catchkhối, vì tôi đã có cùng một mã trong lần thử làm OP. Bạn thực sự nên từ chối hoàn toàn câu hỏi này vì mã của OP sau đó.
MiffTheFox

1
@John, chúng tôi quên đây là mã mẫu. Đây là trường hợp nó là một cách khác để 404, không phải cách sử dụng GetResponse. -1 có vẻ hơi gay gắt. +1 cho Miff để trả lời câu hỏi.
David Basarab

@John Tôi nghĩ bạn chỉ ra nó trong một nhận xét là tốt. Cách tôi xem xét việc bỏ phiếu xuống là nếu mã được đưa ra không giải quyết được vấn đề. Cảm ơn bạn đã bỏ phiếu xuống.
David Basarab

@John - Tốt thôi, tôi đã loại bỏ mọi thứ nhưng bắt được, bây giờ hạnh phúc chứ?
MiffTheFox

4

Tôi nghĩ rằng nếu bạn bắt gặp một WebException, có một số thông tin trong đó mà bạn có thể sử dụng để xác định xem đó có phải là 404. Đó là cách duy nhất tôi biết vào lúc này ... Tôi muốn biết bất kỳ người nào khác ...

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

2

Kiểm tra đoạn trích này. GetResponse sẽ ném ra một WebRequestException. Nắm bắt điều đó và bạn có thể nhận được mã trạng thái từ phản hồi.

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

điều này đến từ http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx


2

Bắt loại ngoại lệ thích hợp 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");
}

@John Saunders Tôi không tranh luận về bạn ở đó, nhưng đó không phải là câu hỏi, anh ấy đã hỏi cách tốt nhất để nắm bắt 404. Những thay đổi của tôi đối với mã của anh ấy chỉ giới hạn ở việc trả lời câu hỏi, để làm cho thay đổi đơn giản và rõ ràng như khả thi.
Nick Craver

@John Saunders: Đã sửa, tôi cho rằng "nếu điều này là hiệu quả nhất" làm cho nó áp dụng cho câu hỏi.
Nick Craver

Chỉ cần truyền e.Responsenhư HttpWebResponsetrước khi có quyền truy cập vào StatusCode.
Lankymart

2

Xem tại MSDN về trạng thái của phản hồi:

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

2
@John Saunders - Tôi sẽ rất vui khi chuyển nó đến MSDN (nơi tôi đã sao chép mẫu từ ...). Mục đích của mã này là để hiển thị việc sử dụng StatusCode, không phải là hiệu quả nhất có thể.
Dror

2
@John Saunders - Tôi chỉ để lại phần tôi muốn hiển thị, Chỉ dành cho bạn :-)
Dror

2

Đối với những người sử dụng VB.NET, tôi tin rằng chúng ta chỉ có thể bắt được ngoại lệ nếu nó thực sự là 404. Một cái gì đó như:

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

khi POST hoặc GET dữ liệu đến máy chủ bằng cách sử dụng lớp WebRequest thì loại ngoại lệ sẽ là WebException. Dưới đây là mã cho tệp không tìm thấy ngoại lệ

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

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