Comment attraper un 404?

93

J'ai le code suivant:

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

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

Comment puis-je détecter une erreur 404 spécifique? WebExceptionStatus.ProtocolError peut uniquement détecter qu'une erreur s'est produite, mais pas donner le code exact de l'erreur.

Par exemple:

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

Ce n'est tout simplement pas assez utile ... l'exception de protocole pourrait être 401, 503, 403, vraiment n'importe quoi.

JL.
la source
13
NNNOOOOOOOOOOOOO! N'attrapez pas System.Exceptionet ne dépendez pas du texte d'exception dans votre gestionnaire!
Aaronaught le
2
La réponse de John Saunders était la plus complète. Je pense que les gens l'ont simplement critiqué par dépit.
Aaronaught
3
Ne pas utiliser throw ex, vous générerez une nouvelle exception avec une pile d'appels vide. Utilisez simplement throw.
krbnr
1
J'ai toujours trouvé cela frustrant moi-même. Une exception ne doit pas être levée si vous obtenez une réponse bien formée et un message d'erreur de protocole est définitivement bien formé. La classe doit permettre à l'utilisateur d'interpréter les résultats et d'agir en conséquence.
Jeremy Holovacs
Les exceptions @JeremyHolovacs ne sont plus lancées pour des choses comme 404 dans les nouveaux clients http. "Ne pas utiliser d'exceptions pour le flux de contrôle" ne semblait pas survivre à l'équipe qui a construitWebRequest
Matt Kocaj

Réponses:

113

Utilisez le HttpStatusCode Enumeration, spécifiquementHttpStatusCode.NotFound

Quelque chose comme:

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


weest un WebException.

Jay Riggs
la source
puis-je obtenir le NOMBRE des objets sans créer ma propre liste de recherche? Je voudrais avoir quelque chose comme: int httpresponsecode = HttpStatusCode.ToInt () ou similaire, donc j'obtiens 404
BerggreenDK
2
@BerggreenDK vous devriez pouvoir simplement faire int httpresonsecode = (int) HttpStatusCode.NotFound
Trev
7
-1 Explication partielle de mon ancien vote négatif: le code lève NullReferenceException si, pour une raison quelconque, we.Responsene l'est pas HttpWebResponse. Si le code souhaite supposer qu'il aura toujours ce type, il devrait simplement jeter: HttpWebResponse errorResponse = (HttpWebResponse)we.Response;. Cela jettera un explicite InvalidCastExceptionsi l'impossible se produit, au lieu d'un mystérieux NullReferenceException.
John Saunders
J'utilise An object reference is required for the non-static field, method, or property 'WebException.Response'ce code.
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
la source
10
lol @ étant la police IDisposable et donnant à chacun un -1 pour ne pas envelopper la réponse dans un bloc using.
Rich
2
C'est un travail difficile, mais quelqu'un doit le faire. OTOH, je n'ai presque pas ajouté cette réponse, car il pourrait sembler que je demandais à tout le monde de faire de la mienne la réponse la mieux notée.
John Saunders
3
En fait, j'ai voté pour, mais j'ai juste remarqué une chose: il devrait probablement y avoir un throw(rethrow) à la fin de votre catch, sinon cela mangera tout autre type de WebException.
Aaronaught le
@John Saunders: Pourquoi n'avez-vous pas également une utilisation autour de votre demande?
Joel Etherton
1
@Joel: WebRequestne met pas en œuvre IDisposable.
John Saunders
23

En C # 6, vous pouvez utiliser des filtres d'exception .

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
}
jeux d'artisanat
la source
Une fonctionnalité très cool que j'ai négligée! J'ai continué à chercher des méthodes pour attraper seulement 401 tout en laissant les autres passer au gestionnaire d'exceptions général. C'est la voie à suivre!
Lionet Chen
12

Je n'ai pas testé ça, mais ça devrait marcher

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
la source
@John Saunders - J'adaptais le code de l'OP, je ne l'optimisais pas.
MiffTheFox
@John - Et peut-être que je m'attendais seulement à ce qu'ils copient / collent le catchbloc, vu que j'avais exactement le même code dans l'essai que l'OP. Vous devriez vraiment évoquer complètement cette question à cause du code de l'OP.
MiffTheFox
1
@John nous oublions ici est un exemple de code. C'est le cas, c'est une autre façon de 404, pas comment utiliser GetResponse. -1 semble un peu dur. +1 à Miff pour avoir répondu à la question.
David Basarab
@John Je pense que c'est bien de le signaler dans un commentaire. La façon dont je regarde le vote vers le bas est si le code donné ne résout pas le problème. Merci d'avoir supprimé le vote négatif.
David Basarab
@John - Très bien, je me suis débarrassé de tout sauf du piège, heureux maintenant?
MiffTheFox
4

Je pense que si vous attrapez une WebException, il y a des informations là-dedans que vous pouvez utiliser pour déterminer s'il s'agissait d'un 404. C'est le seul moyen que je connaisse pour le moment ... J'aimerais en connaître d'autres ...

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

Découvrez ce snipit. GetResponse lèvera une WebRequestException. Attrapez cela et vous pouvez obtenir le code d'état à partir de la réponse.

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

cela vient de http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx

Jonathan S.
la source
2

Attrapez le type d'exception approprié 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
la source
@John Saunders Je ne vous débat pas là-bas, mais ce n'était pas la question, il a demandé la meilleure façon de capturer un 404. Mes modifications de son code se sont limitées à répondre à la question, pour rendre le changement aussi simple et évident que possible.
Nick Craver
@John Saunders: Corrigé, je suppose que "si c'est le plus efficace", cela s'applique à la question.
Nick Craver
Il fallait juste lancer le e.Responsecomme HttpWebResponseavant d'accéder au StatusCode.
Lankymart
2

Consultez MSDN sur l'état de la réponse:

...
catch(WebException e) {
  Console.WriteLine("The following error occured : {0}",e.Status);  
}
...
Dror
la source
2
@John Saunders - Je serai plus qu'heureux de le transmettre à MSDN (où j'ai copié l'échantillon à partir de ...). Le but de ce code est de montrer l'utilisation de StatusCode, pas d'être aussi efficace que possible.
Dror
2
@John Saunders - Je n'ai laissé que la partie que je voulais montrer, rien que pour vous :-)
Dror
2

Pour les gens de VB.NET qui parcourent ceci, je crois que nous ne pouvons attraper l'exception que s'il s'agit vraiment d'un 404. Quelque chose comme:

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
inconnu
la source
1

lorsque les données POST ou GET sur le serveur à l'aide de la classe WebRequest, le type d'exception serait WebException.Voici le code pour l'exception de fichier introuvable

        //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
la source