Come ottenere informazioni sugli errori quando HttpWebRequest.GetResponse () non riesce


87

Sto avviando un HttpWebRequest e quindi recuperando la sua risposta. Di tanto in tanto, ottengo un errore 500 (o almeno 5 ##), ma nessuna descrizione. Ho il controllo su entrambi gli endpoint e vorrei che il destinatario ricevesse un po 'più di informazioni. Ad esempio, vorrei passare il messaggio di eccezione dal server al client. È possibile utilizzare HttpWebRequest e HttpWebResponse?

Codice:

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)."
}

Qualsiasi aiuto con questo sarebbe molto apprezzato.


Aggiungerò solo a questo, è sempre consigliabile ridurre al minimo il contenuto racchiuso da tryun'istruzione. Nel tuo caso, tutto fino alla usingriga potrebbe probabilmente essere scritto all'esterno.
SSHunter49

Risposte:


153

È possibile utilizzare HttpWebRequest e HttpWebResponse?

Potresti fare in modo che il tuo server web rilevi e scriva il testo dell'eccezione nel corpo della risposta, quindi imposti il ​​codice di stato su 500. Ora il client lancia un'eccezione quando incontra un errore 500 ma potresti leggere il flusso di risposta e recuperare il messaggio dell'eccezione.

Quindi potresti catturare una WebException che è ciò che verrà lanciato se un codice di stato non 200 viene restituito dal server e leggi il suo corpo:

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
}

Grazie! È importante notare che il flusso dall'interno dell'istruzione using non sarà disponibile all'esterno dell'istruzione using, poiché il dispositivo di smaltimento di WebResponse lo cancellerà. Questo mi ha fatto inciampare per alcuni minuti.
Thorin

@Thorin. Il "flusso" dalla prima affermazione viene portato a quella successiva. Proprio come in un'istruzione IF a riga singola, ad esempio if (something) do-stuff-here;
RealityDysfunction

1
GetRequestStreame GetResponsepuò generare eccezioni ?
PreguntonCojoneroCabrón

@ PreguntonCojoneroCabrón Sì, non sembra proprio vero, lo fa. Per fortuna Microsoft ha introdotto la classe HttpClient, che sospetto la maggior parte stia utilizzando in questi giorni. msdn.microsoft.com/en-us/library/…
Morten Nørgaard

8

Mi sono imbattuto in questa domanda durante il tentativo di verificare se un file esisteva su un sito FTP o meno. Se il file non esiste, si verificherà un errore durante il tentativo di controllare il suo timestamp. Ma voglio assicurarmi che l'errore non sia qualcos'altro, controllandone il tipo.

La Responseproprietà su WebExceptionsarà del tipo FtpWebResponsesu cui puoi controllare la sua StatusCodeproprietà per vedere quale errore FTP hai.

Ecco il codice con cui sono finito:

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

4

Ho affrontato una situazione simile:

Stavo cercando di leggere la risposta grezza in caso di un errore HTTP che consumava un servizio SOAP, utilizzando BasicHTTPBinding.

Tuttavia, durante la lettura della risposta utilizzando GetResponseStream(), ha ottenuto l'errore:

Stream non leggibile

Quindi, questo codice ha funzionato per me:

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

0

È inoltre possibile utilizzare questa libreria che racchiude HttpWebRequest e Response in metodi semplici che restituiscono oggetti in base ai risultati. Utilizza alcune delle tecniche descritte in queste risposte e ha un sacco di codice ispirato alle risposte da questo e altri thread simili. Cattura automaticamente tutte le eccezioni, cerca di astrarre quanto più codice boilerplate possibile per effettuare queste richieste Web il più possibile e deserializza automaticamente l'oggetto risposta.

Un esempio di come sarebbe il tuo codice usando questo wrapper è semplice come

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

    }

Divulgazione completa Questa libreria è una libreria wrapper open source gratuita e io sono l'autore di detta libreria. Non ci guadagno niente, ma l'ho trovato immensamente utile nel corso degli anni e sono sicuro che lo farà anche chiunque stia ancora utilizzando le classi HttpWebRequest / HttpWebResponse.

Non è un proiettile d'argento ma supporta get, post, delete sia con async che non async per get e post, nonché richieste e risposte JSON o XML. Viene mantenuto attivamente a partire dal 21/6/2020


-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(); 
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.