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

J L.
źródło
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.

Jay Riggs
źródło
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
    }
}
John Saunders
źródło
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
}
gry rzemieślnicze
źródło
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;
}
MiffTheFox
źródło
@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);
    }
}
mezoid
źródło
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

Jonathan S.
źródło
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");
}
Nick Craver
źródło
@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);  
}
...
Dror
źródło
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
nieznany
źródło
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);
                    }

                }
Sheo Dayal Singh
źródło