Jak uzyskać informacje o błędzie, gdy HttpWebRequest.GetResponse () nie powiedzie się

86

Inicjuję HttpWebRequest, a następnie pobieram jego odpowiedź. Czasami otrzymuję błąd 500 (lub co najmniej 5 ##), ale nie ma opisu. Mam kontrolę nad obydwoma punktami końcowymi i chciałbym, aby odbiorca uzyskał trochę więcej informacji. Na przykład chciałbym przekazać komunikat o wyjątku z serwera do klienta. Czy jest to możliwe przy użyciu HttpWebRequest i HttpWebResponse?

Kod:

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

Jakakolwiek pomoc w tej sprawie byłaby bardzo mile widziana.

Trevor
źródło

Odpowiedzi:

151

Czy jest to możliwe przy użyciu HttpWebRequest i HttpWebResponse?

Można by serwer WWW po prostu przechwytywał i zapisywał tekst wyjątku w treści odpowiedzi, a następnie ustawiał kod statusu na 500. Teraz klient zgłosiłby wyjątek, gdy napotka błąd 500, ale można by odczytać strumień odpowiedzi i pobrać wiadomość o wyjątku.

Możesz więc złapać WebException, który zostanie wyrzucony, jeśli kod stanu inny niż 200 zostanie zwrócony z serwera i przeczyta jego treść :

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
źródło
Dziękuję Ci! Należy pamiętać, że strumień z wnętrza instrukcji using nie będzie dostępny poza instrukcją using, ponieważ usuwający WebResponse go wyczyści. To mnie zaskoczyło na kilka minut.
Thorin
@Thorin. „Strumień” z pierwszej instrukcji jest przenoszony do następnej instrukcji. Tak jak w pojedynczej linii instrukcji IF, na przykład jeśli (coś) zrób-tu-rzecz;
RealityDysfunction
1
GetRequestStreami GetResponsemoże rzucać wyjątki ?
PreguntonCojoneroCabrón
@ PreguntonCojoneroCabrón Tak, nie wydaje się to całkiem w porządku, prawda. Na szczęście Microsoft wprowadził klasę HttpClient, której, jak podejrzewam, używa obecnie w większości. msdn.microsoft.com/en-us/library/…
Morten Nørgaard
8

Natknąłem się na to pytanie, próbując sprawdzić, czy plik istnieje w witrynie FTP, czy nie. Jeśli plik nie istnieje, podczas próby sprawdzenia jego sygnatury czasowej wystąpi błąd. Ale chcę się upewnić, że błąd nie jest czymś innym, sprawdzając jego typ.

ResponseNieruchomość na WebExceptionbędzie od rodzaju FtpWebResponse, na którym można sprawdzić swoją StatusCodewłaściwość, aby zobaczyć , które FTP error masz.

Oto kod, który otrzymałem:

    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
źródło
4

Miałem podobną sytuację:

Próbowałem odczytać nieprzetworzoną odpowiedź w przypadku błędu HTTP zużywającego usługę SOAP, używając BasicHTTPBinding.

Jednak podczas czytania odpowiedzi za pomocą GetResponseStream()otrzymałem błąd:

Strumień nieczytelny

Tak więc ten kod zadziałał dla mnie:

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
źródło
0

Możesz również użyć tej biblioteki, która opakowuje HttpWebRequest i Response w proste metody, które zwracają obiekty na podstawie wyników. Wykorzystuje niektóre z technik opisanych w tych odpowiedziach i zawiera mnóstwo kodu inspirowanego odpowiedziami z tego i podobnych wątków. Automatycznie wyłapuje wszelkie wyjątki, stara się wyodrębnić jak najwięcej kodu źródłowego potrzebnego do wykonania tych żądań internetowych, a także automatycznie deserializuje obiekt odpowiedzi.

Przykład tego, jak wyglądałby Twój kod przy użyciu tego opakowania, jest tak prosty jak

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

    }

Pełne ujawnienie Ta biblioteka jest bezpłatną biblioteką opakowaniową typu open source, a ja jestem jej autorem. Nie zarabiam na tym żadnych pieniędzy, ale przez lata odkryłem, że jest to niezwykle przydatne i jestem pewien, że każdy, kto nadal korzysta z klas HttpWebRequest / HttpWebResponse, też to zrobi.

Nie jest to srebrny punktor, ale obsługuje pobieranie, wysyłanie, usuwanie zarówno z asynchronicznymi, jak i nie-asynchronicznymi dla pobierania i wysyłania, a także żądania i odpowiedzi JSON lub XML. Jest aktywnie utrzymywany od 21.06.2020 r

pat8719
źródło
-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
źródło