Jak mogę złapać 404?


95

Mam następujący kod:

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

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

Jak mogę złapać określony błąd 404? WebExceptionStatus.ProtocolError może tylko wykryć wystąpienie błędu, ale nie podaje dokładnego kodu błędu.

Na przykład:

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

Po prostu nie jest wystarczająco przydatne ... wyjątek protokołu może mieć wartość 401, 503, 403, cokolwiek naprawdę.


13
NNNOOOOOOOOOOOOO! Nie łapaj System.Exceptioni nie polegaj na tekście wyjątku w swoim module obsługi!
— Aaronaught

2
Odpowiedź Johna Saundersa była najbardziej kompletna. Myślę, że ludzie po prostu zlekceważyli go na przekór.
— Aaronaught

3
Nie używaj throw ex, wygenerujesz nowy wyjątek z pustym stosem wywołań. Po prostu użyj throw.
— krbnr

1
Ja zawsze uważałem to za frustrujące. Nie należy zgłaszać wyjątku, jeśli otrzymasz poprawnie sformułowaną odpowiedź, a komunikat o błędzie protokołu jest zdecydowanie poprawnie sformułowany. Klasa powinna umożliwiać użytkownikowi interpretację wyników i odpowiednie działanie.
— Jeremy Holovacs

Wyjątki @JeremyHolovacs nie są już generowane dla rzeczy takich jak 404 w nowszych klientach http. Wydaje się, że „Nie używaj wyjątków dla przepływu kontroli” nie przetrwało zespołu, który zbudowałWebRequest
— Matt Kocaj,

Odpowiedzi:


115

Użyj w HttpStatusCode EnumerationszczególnościHttpStatusCode.NotFound

Coś jak:

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

Gdzie
wejest WebException.


czy mogę jakoś wydobyć NUMBER z obiektów bez tworzenia własnej listy odnośników? Chciałbym mieć coś takiego: int httpresponsecode = HttpStatusCode.ToInt () lub podobny, więc otrzymuję 404
— BerggreenDK

2
@BerggreenDK powinieneś być w stanie po prostu wykonać int httpresonsecode = (int) HttpStatusCode.NotFound
— Trev

8
-1 Częściowe wyjaśnienie mojej starożytnej opinii negatywnej: kod rzuca wyjątek NullReferenceException, jeśli z jakiegoś powodu we.Responsetak nie jest HttpWebResponse. Jeśli kod pragnie założyć, że będzie zawsze mają tego typu, to powinien po prostu obsada: HttpWebResponse errorResponse = (HttpWebResponse)we.Response;. Spowoduje to rzucenie wyraźnego, InvalidCastExceptionjeśli stanie się niemożliwe, zamiast tajemniczego NullReferenceException.
— John Saunders,

Używam An object reference is required for the non-static field, method, or property 'WebException.Response'tego kodu.
— 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 @ jest policją IDisposable i daje każdemu -1 za nie zawijanie odpowiedzi w blok using.
— Rich

2
To ciężka praca, ale ktoś musi to zrobić. OTOH, prawie nie dodałem tej odpowiedzi, ponieważ mogłoby się wydawać, że dzwoniłem do wszystkich innych, aby moja odpowiedź była najwyżej oceniana.
— John Saunders

3
Właściwie zagłosowałem za, ale właśnie zauważyłem jedną rzecz: prawdopodobnie powinno być throw( ponowne rzucenie ) na końcu twojego catch, w przeciwnym razie po cichu zje każdy inny rodzaj WebException.
— Aaronaught

@John Saunders: Dlaczego nie wykorzystasz również swojej prośby?
— Joel Etherton

1
@Joel: WebRequestnie implementuje IDisposable.
— John Saunders

24

W C # 6 możesz używać filtrów wyjątków .

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
}

Bardzo fajna funkcja, którą przeoczyłem! Szukałem metod, aby złapać tylko 401, jednocześnie pozwalając innym przejść do ogólnego programu obsługi wyjątków. To jest odpowiednie rozwiązanie!
— Lionet Chen

Znakomicie, to powinna być akceptowana odpowiedź.
— Lucas925

12

Nie testowałem tego, ale powinno działać

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 - dostosowywałem kod OP, a nie optymalizowałem go.
— MiffTheFox

@John - I może spodziewałem się tylko, że skopiują / wkleią catchblok, ponieważ miałem dokładnie ten sam kod w próbie co OP. Naprawdę powinieneś całkowicie zlekceważyć to pytanie z powodu kodu OP.
— MiffTheFox

1
@John, o którym zapomnieliśmy, to przykładowy kod. Jest to inny sposób 404, a nie sposób korzystania z GetResponse. -1 wydaje się trochę szorstki. +1 dla Miff za odpowiedź na pytanie.
— David Basarab

@John Myślę, że to dobrze, że wskazałeś to w komentarzu. Sposób, w jaki patrzę na głosowanie w dół, polega na tym, że podany kod nie rozwiązuje problemu. Dziękuję za usunięcie głosu przeciwnego.
— David Basarab

@John - Dobra, pozbyłem się wszystkiego oprócz haczyka, szczęśliwy teraz?
— MiffTheFox

4

Myślę, że jeśli złapiesz WebException , jest tam kilka informacji, których możesz użyć do ustalenia, czy to 404. To jedyny sposób, jaki znam w tej chwili ... Chciałbym poznać inne ...

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

2

Sprawdź ten fragment. GetResponse zgłosi wyjątek WebRequestException. Złap to i możesz uzyskać kod stanu z odpowiedzi.

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

pochodzi z http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx


2

Złap odpowiedni typ wyjątku 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 Nie dyskutuję tam z tobą, ale to nie było pytanie, zadał najlepszy sposób, aby uchwycić 404. Moje zmiany w jego kodzie ograniczały się do odpowiedzi na pytanie, aby zmiana była tak prosta i oczywista jak możliwy.
— Nick Craver

@John Saunders: Naprawiono, przypuszczam, że „jeśli to jest najbardziej wydajne” sprawia, że ​​odnosi się to do pytania.
— Nick Craver

Po prostu musiałem rzucić e.Responsejak HttpWebResponseprzed uzyskaniem dostępu do StatusCode.
— Lankymart

2

Zobacz w MSDN o stanie odpowiedzi:

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

2
@John Saunders - z przyjemnością przekażę go do MSDN (gdzie skopiowałem próbkę z ...). Celem tego kodu jest pokazanie użycia StatusCode, a nie zapewnienie jak największej wydajności.
— Dror

2
@John Saunders - Zostawiłem tylko część, którą chciałem pokazać, Tylko dla Ciebie :-)
— Dror

2

Dla osób przeglądających to VB.NET uważam, że możemy złapać wyjątek tylko wtedy, gdy naprawdę jest to 404. Coś takiego:

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

gdy POST lub GET dane do serwera przy użyciu klasy WebRequest, typ wyjątku będzie WebException. poniżej znajduje się kod dla wyjątku nie znaleziono pliku

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

                }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.