Come posso prendere un 404?


93

Ho il codice seguente:

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

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

Come posso rilevare un errore 404 specifico? WebExceptionStatus.ProtocolError può solo rilevare che si è verificato un errore, ma non fornire il codice esatto dell'errore.

Per esempio:

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

Semplicemente non è abbastanza utile ... l'eccezione del protocollo potrebbe essere 401, 503, 403, qualsiasi cosa.


13
NNNOOOOOOOOOOOOO! Non prendere System.Exceptione non dipendere dal testo dell'eccezione nel tuo gestore!
Aaronaught

2
La risposta di John Saunders è stata la più completa. Penso che le persone lo abbiano semplicemente svalutato per dispetto.
Aaronaught

3
Non usare throw ex, genererai una nuova eccezione con uno stack di chiamate vuoto. Basta usare throw.
krbnr

1
L'ho sempre trovato frustrante, io stesso. Non dovrebbe essere generata un'eccezione se si ottiene una risposta ben formata e un messaggio di errore del protocollo è sicuramente ben formato. La classe dovrebbe consentire all'utente di interpretare i risultati e agire di conseguenza.
Jeremy Holovacs

Le eccezioni di @JeremyHolovacs non vengono più lanciate per cose come 404 nei client http più recenti. "Non usare eccezioni per il flusso di controllo" non sembra sopravvivere alla squadra che ha costruitoWebRequest
Matt Kocaj

Risposte:


113

Usa HttpStatusCode Enumeration, in particolareHttpStatusCode.NotFound

Qualcosa di simile a:

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

Dov'è
weun file WebException.


posso estrarre il NUMERO in qualche modo dagli oggetti senza creare il mio elenco di ricerca? Vorrei avere qualcosa del tipo: intescorepresponsecode = HttpStatusCode.ToInt () o simile in modo da ottenere 404
BerggreenDK

2
@BerggreenDK dovresti essere in grado di fare solo intmospherpresonsecode = (int) HttpStatusCode.NotFound
Trev

7
-1 Spiegazione parziale del mio antico voto negativo: il codice genera NullReferenceException se, per qualche motivo, we.Responsenon lo è HttpWebResponse. Se il codice vuole assumere che avrà sempre quel tipo, allora dovrebbe semplicemente espressi: HttpWebResponse errorResponse = (HttpWebResponse)we.Response;. Questo lancerà un esplicito InvalidCastExceptionse accade l'impossibile, invece di un misterioso NullReferenceException.
John Saunders

Ottengo An object reference is required for the non-static field, method, or property 'WebException.Response'utilizzando questo codice.
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 @ essendo la polizia IDisposable e dando a tutti un -1 per non aver racchiuso la risposta in un blocco using.
Rich

2
È un lavoro duro, ma qualcuno deve farlo. OTOH, quasi non ho aggiunto questa risposta, dal momento che potrebbe sembrare che stessi colpendo tutti gli altri per rendere la mia la risposta più votata.
John Saunders,

3
In realtà ho votato positivamente, ma ho notato solo una cosa: probabilmente dovrebbe esserci un throw(rilancio) alla fine del tuo catch, altrimenti questo mangerà silenziosamente qualsiasi altro tipo di WebException.
Aaronaught

@ John Saunders: Perché non usi anche la tua richiesta?
Joel Etherton

1
@ Joel: WebRequestnon implementa IDisposable.
John Saunders

23

In C # 6 è possibile utilizzare filtri di eccezione .

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
}

Una caratteristica molto interessante che ho trascurato! Ho continuato a cercare metodi per catturare solo 401 mentre lasciavo che altri passassero al gestore di eccezioni generale. Questa è la strada da percorrere!
Lionet Chen

12

Non l'ho testato, ma dovrebbe funzionare

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 - Stavo adattando il codice dell'OP, non ottimizzandolo.
MiffTheFox

@ John - E forse mi aspettavo solo che copiassero / incollassero il catchblocco, visto che avevo lo stesso identico codice nel tentativo dell'OP. Dovresti davvero eliminare completamente questa domanda a causa del codice dell'OP.
MiffTheFox

1
@ John ci dimentichiamo qui è un codice di esempio. Questo è il caso in cui è un altro modo per 404, non come usare GetResponse. -1 sembra un po 'duro. +1 a Miff per aver risposto alla domanda.
David Basarab

@ Giovanni credo sia bene che tu lo indichi in un commento. Il modo in cui guardo al voto negativo è se il codice fornito non risolve il problema. Grazie per aver rimosso il voto negativo.
David Basarab

@ John - Bene, mi sono sbarazzato di tutto tranne che del pescato, contento adesso?
MiffTheFox

4

Penso che se catturi una WebException ci siano alcune informazioni lì dentro che puoi usare per determinare se era un 404. Questo è l'unico modo che conosco al momento ... Sarei interessato a conoscerne altri ...

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

2

Dai un'occhiata a questo snipit. GetResponse genererà un'eccezione WebRequestException. Prendilo e puoi ottenere il codice di stato dalla risposta.

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

questo proveniva da http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx


2

Cattura il tipo di eccezione corretto 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 Non ti discuto lì, ma non era questa la domanda, ha chiesto il modo migliore per catturare un 404. Le mie modifiche al suo codice si sono limitate a rispondere alla domanda, per rendere la modifica semplice e ovvia come possibile.
Nick Craver

@ John Saunders: Risolto, suppongo che "se questo è il più efficiente" lo faccia applicare alla domanda.
Nick Craver

Dovevo solo lanciare il e.Responsecome HttpWebResponseprima di ottenere l'accesso al StatusCode.
Lankymart

2

Vedere su MSDN lo stato della risposta:

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

2
@ John Saunders - Sarò più che felice di passarlo a MSDN (da dove ho copiato il campione da ...). Lo scopo di questo codice è mostrare l'utilizzo di StatusCode, non essere il più efficiente possibile.
Dror

2
@ John Saunders - Ho lasciato solo la parte che volevo mostrare, solo per te :-)
Dror

2

Per le persone di VB.NET che lo esplorano, credo che possiamo catturare l'eccezione solo se è veramente un 404. Qualcosa come:

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

quando POST o GET dati al server utilizzando la classe WebRequest, il tipo di eccezione sarebbe WebException. Di seguito è riportato il codice per l'eccezione file non trovata

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

                }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.