Comment obtenir des informations d'erreur lorsque HttpWebRequest.GetResponse () échoue

86

Je lance une HttpWebRequest, puis je récupère sa réponse. Parfois, j'obtiens une erreur 500 (ou au moins 5 ##), mais aucune description. J'ai le contrôle sur les deux points d'extrémité et j'aimerais que l'extrémité de réception reçoive un peu plus d'informations. Par exemple, je voudrais transmettre le message d'exception du serveur au client. Est-ce possible en utilisant HttpWebRequest et HttpWebResponse?

Code:

try
{
    HttpWebRequest webRequest = HttpWebRequest.Create(URL) as HttpWebRequest;
    webRequest.Method = WebRequestMethods.Http.Get;
    webRequest.Credentials = new NetworkCredential(Username, Password);
    webRequest.ContentType = "application/x-www-form-urlencoded";
    using(HttpWebResponse response = webRequest.GetResponse() as HttpWebResponse)
    {
        if(response.StatusCode == HttpStatusCode.OK)
        {
            // Do stuff with response.GetResponseStream();
        }
    }
}
catch(Exception ex)
{
    ShowError(ex);
    // if the server returns a 500 error than the webRequest.GetResponse() method
    // throws an exception and all I get is "The remote server returned an error: (500)."
}

Toute aide à ce sujet serait très appréciée.

Trevor
la source

Réponses:

151

Est-ce possible en utilisant HttpWebRequest et HttpWebResponse?

Vous pouvez demander à votre serveur Web d’attraper et d’écrire simplement le texte de l’exception dans le corps de la réponse, puis de définir le code d’état sur 500. Désormais, le client lèverait une exception lorsqu'il rencontrait une erreur 500, mais vous pourriez lire le flux de réponse et récupérer le message de l'exception.

Vous pouvez donc attraper une WebException qui sera lancée si un code d'état non 200 est renvoyé par le serveur et lit son corps:

catch (WebException ex)
{
    using (var stream = ex.Response.GetResponseStream())
    using (var reader = new StreamReader(stream))
    {
        Console.WriteLine(reader.ReadToEnd());
    }
}
catch (Exception ex)
{
    // Something more serious happened
    // like for example you don't have network access
    // we cannot talk about a server exception here as
    // the server probably was never reached
}
Darin Dimitrov
la source
Merci! Il est important de noter que le flux à l'intérieur de l'instruction using ne sera pas disponible en dehors de l'instruction using, car le éliminateur de WebResponse l'effacera. Cela m'a fait trébucher pendant quelques minutes.
Thorin
@Thorin. Le "flux" de la première instruction est transféré à l'instruction suivante. Tout comme dans une instruction IF sur une seule ligne, par exemple if (quelque chose) do-stuff-here;
RéalitéDysfonction
1
GetRequestStreamet GetResponsepeut jeter des exceptions ?
PreguntonCojoneroCabrón
@ PreguntonCojoneroCabrón Oui, cela ne semble pas tout à fait correct, n'est-ce pas. Heureusement, Microsoft a introduit la classe HttpClient, que je suppose que la plupart utilisent ces jours-ci. msdn.microsoft.com/en-us/library/…
Morten Nørgaard
8

Je suis tombé sur cette question en essayant de vérifier si un fichier existait sur un site FTP ou non. Si le fichier n'existe pas, une erreur se produira lors de la tentative de vérification de son horodatage. Mais je veux m'assurer que l'erreur n'est pas autre chose, en vérifiant son type.

le Response propriété sur WebExceptionsera du type FtpWebResponsesur lequel vous pouvez vérifier sa StatusCodepropriété pour voir quelle erreur FTP vous avez.

Voici le code avec lequel j'ai fini:

    public static bool FileExists(string host, string username, string password, string filename)
    {
        // create FTP request
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + host + "/" + filename);
        request.Credentials = new NetworkCredential(username, password);

        // we want to get date stamp - to see if the file exists
        request.Method = WebRequestMethods.Ftp.GetDateTimestamp;

        try
        {
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            var lastModified = response.LastModified;

            // if we get the last modified date then the file exists
            return true;
        }
        catch (WebException ex)
        {
            var ftpResponse = (FtpWebResponse)ex.Response;

            // if the status code is 'file unavailable' then the file doesn't exist
            // may be different depending upon FTP server software
            if (ftpResponse.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
            {
                return false;
            }

            // some other error - like maybe internet is down
            throw;
        }
    }
Simon_Weaver
la source
4

J'ai fait face à une situation similaire:

J'essayais de lire la réponse brute en cas d'erreur HTTP consommant un service SOAP, en utilisant BasicHTTPBinding.

Cependant, lors de la lecture de la réponse à l'aide de GetResponseStream(), vous avez obtenu l'erreur:

Flux non lisible

Donc, ce code a fonctionné pour moi:

try
{
    response = basicHTTPBindingClient.CallOperation(request);
}
catch (ProtocolException exception)
{
    var webException = exception.InnerException as WebException;
    var rawResponse = string.Empty;

    var alreadyClosedStream = webException.Response.GetResponseStream() as MemoryStream;
    using (var brandNewStream = new MemoryStream(alreadyClosedStream.ToArray()))
    using (var reader = new StreamReader(brandNewStream))
        rawResponse = reader.ReadToEnd();
}
João Paulo Melo
la source
0

Vous pouvez également utiliser cette bibliothèque qui encapsule HttpWebRequest et Response dans des méthodes simples qui renvoient des objets en fonction des résultats. Il utilise certaines des techniques décrites dans ces réponses et contient beaucoup de code inspiré des réponses de ce sujet et de fils similaires. Il détecte automatiquement toutes les exceptions, cherche à extraire autant de code chaudière que possible pour effectuer ces requêtes Web et désérialise automatiquement l'objet de réponse.

Un exemple de ce à quoi votre code ressemblerait en utilisant ce wrapper est aussi simple que

    var response = httpClient.Get<SomeResponseObject>(request);
    
    if(response.StatusCode == HttpStatusCode.OK)
    {
        //do something with the response
        console.Writeline(response.Body.Id); //where the body param matches the object you pass in as an anonymous type.  
    }else {
         //do something with the error
         console.Writelint(string.Format("{0}: {1}", response.StatusCode.ToString(), response.ErrorMessage);

    }

Divulgation complète Cette bibliothèque est une bibliothèque de wrapper open source gratuite, et je suis l'auteur de ladite bibliothèque. Je ne gagne pas d'argent avec cela, mais je l'ai trouvé extrêmement utile au fil des ans et je suis sûr que quiconque utilise encore les classes HttpWebRequest / HttpWebResponse le fera aussi.

Ce n'est pas une solution miracle mais prend en charge get, post, delete avec à la fois async et non async pour get et post ainsi que les demandes et réponses JSON ou XML. Il est activement maintenu à partir du 21/06/2020

pat8719
la source
-3
HttpWebRequest myHttprequest = null;
HttpWebResponse myHttpresponse = null;
myHttpRequest = (HttpWebRequest)WebRequest.Create(URL);
myHttpRequest.Method = "POST";
myHttpRequest.ContentType = "application/x-www-form-urlencoded";
myHttpRequest.ContentLength = urinfo.Length;
StreamWriter writer = new StreamWriter(myHttprequest.GetRequestStream());
writer.Write(urinfo);
writer.Close();
myHttpresponse = (HttpWebResponse)myHttpRequest.GetResponse();
if (myHttpresponse.StatusCode == HttpStatusCode.OK)
 {
   //Perform necessary action based on response
 }
myHttpresponse.Close(); 
Pranesh Janarthanan
la source