Cómo obtener información de error cuando falla HttpWebRequest.GetResponse ()

86

Estoy iniciando una HttpWebRequest y luego recupero su respuesta. Ocasionalmente, obtengo un error 500 (o al menos 5 ##), pero sin descripción. Tengo control sobre ambos extremos y me gustaría que el extremo receptor obtenga un poco más de información. Por ejemplo, me gustaría pasar el mensaje de excepción del servidor al cliente. ¿Es esto posible usando HttpWebRequest y HttpWebResponse?

Código:

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

Cualquier ayuda con esto sería muy apreciada.

Trevor
fuente

Respuestas:

151

¿Es esto posible usando HttpWebRequest y HttpWebResponse?

Puede hacer que su servidor web simplemente capture y escriba el texto de la excepción en el cuerpo de la respuesta, luego establezca el código de estado en 500. Ahora el cliente lanzaría una excepción cuando encuentre un error 500, pero podría leer el flujo de respuesta y obtener el mensaje de la excepción.

Por lo tanto, podría detectar una WebException, que es lo que se lanzará si el servidor devuelve un código de estado que no sea 200 y lea su cuerpo:

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
fuente
¡Gracias! Es importante tener en cuenta que la secuencia desde el interior de la declaración using no estará disponible fuera de la declaración using, ya que el eliminador de WebResponse la borrará. Esto me hizo tropezar durante unos minutos.
Thorin
@Thorin. El "flujo" de la primera declaración se continúa con la siguiente declaración. Al igual que en una declaración IF de una sola línea, por ejemplo si (algo) hacer-cosas-aquí;
RealityDysfunction
1
GetRequestStreamy GetResponsepuede lanzar excepciones ?
PreguntonCojoneroCabrón
@ PreguntonCojoneroCabrón Sí, no me parece del todo correcto, ¿verdad? Afortunadamente, Microsoft introdujo la clase HttpClient, que sospecho que la mayoría está usando estos días. msdn.microsoft.com/en-us/library/…
Morten Nørgaard
8

Me encontré con esta pregunta al intentar verificar si un archivo existía en un sitio FTP o no. Si el archivo no existe, habrá un error al intentar verificar su marca de tiempo. Pero quiero asegurarme de que el error no sea otra cosa, comprobando su tipo.

La Responsepropiedad en WebExceptionserá del tipo FtpWebResponseen el que puede verificar su StatusCodepropiedad para ver qué error de FTP tiene.

Aquí está el código con el que terminé:

    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
fuente
4

Enfrenté una situación similar:

Estaba tratando de leer la respuesta sin procesar en caso de un error HTTP consumiendo un servicio SOAP, usando BasicHTTPBinding.

Sin embargo, al leer la respuesta usando GetResponseStream(), obtuve el error:

Transmisión no legible

Entonces, este código funcionó para mí:

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
fuente
0

También puedes usar esta biblioteca que envuelve HttpWebRequest y Response en métodos simples que devuelven objetos según los resultados. Utiliza algunas de las técnicas descritas en estas respuestas y tiene mucho código inspirado en respuestas de este y otros hilos similares. Detecta automáticamente cualquier excepción, busca abstraer la mayor cantidad posible de código de placa de caldera necesario para realizar estas solicitudes web y deserializa automáticamente el objeto de respuesta.

Un ejemplo de cómo se vería su código usando este contenedor es tan simple como

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

    }

Divulgación completa Esta biblioteca es una biblioteca contenedora de código abierto gratuita, y yo soy el autor de dicha biblioteca. No gano dinero con esto, pero lo he encontrado inmensamente útil a lo largo de los años y estoy seguro de que cualquiera que todavía esté usando las clases HttpWebRequest / HttpWebResponse también lo hará.

No es una solución milagrosa, pero admite get, post, delete con async y no async para get y post, así como solicitudes y respuestas JSON o XML. Se mantiene activamente a partir del 21/6/2020.

pat8719
fuente
-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
fuente