Como obter informações de erro quando HttpWebRequest.GetResponse () falha

86

Estou iniciando um HttpWebRequest e, em seguida, recuperando sua resposta. Ocasionalmente, recebo um erro 500 (ou pelo menos 5 ##), mas nenhuma descrição. Tenho controle sobre os dois terminais e gostaria que o terminal receptor recebesse mais informações. Por exemplo, gostaria de passar a mensagem de exceção do servidor para o cliente. Isso é possível usando HttpWebRequest e 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)."
}

Qualquer ajuda com isso seria muito apreciada.

Trevor
fonte

Respostas:

151

Isso é possível usando HttpWebRequest e HttpWebResponse?

Você poderia fazer com que seu servidor da web simplesmente capturasse e escrevesse o texto da exceção no corpo da resposta e, em seguida, defina o código de status para 500. Agora, o cliente lançaria uma exceção quando encontrasse um erro 500, mas você poderia ler o fluxo de resposta e buscar o mensagem da exceção.

Portanto, você pode capturar uma WebException que será lançada se um código de status diferente de 200 for retornado do servidor e ler seu 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
}
Darin Dimitrov
fonte
Obrigado! É importante observar que o fluxo de dentro da instrução using não estará disponível fora da instrução using, pois o disposer do WebResponse o limpará. Isso me fez tropeçar por alguns minutos.
Thorin
@Thorin. O "fluxo" da primeira instrução é levado para a próxima instrução. Exatamente como em uma instrução IF de linha única, por exemplo if (something) do-stuff-here;
RealityDysfunction de
1
GetRequestStreame GetResponsepode lançar exceções ?
PreguntonCojoneroCabrón
@ PreguntonCojoneroCabrón Sim, não parece muito certo, não é? Felizmente, a Microsoft introduziu a classe HttpClient, que suspeito que a maioria esteja usando atualmente. msdn.microsoft.com/en-us/library/…
Morten Nørgaard
8

Me deparei com essa pergunta ao tentar verificar se um arquivo existe em um site FTP ou não. Se o arquivo não existir, ocorrerá um erro ao tentar verificar seu carimbo de data / hora. Mas quero ter certeza de que o erro não é outra coisa, verificando seu tipo.

A Responsepropriedade em WebExceptionserá do tipo FtpWebResponseem que você pode verificar sua StatusCodepropriedade para ver qual erro de FTP você tem.

Este é o código que terminei com:

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

Eu enfrentei uma situação semelhante:

Eu estava tentando ler a resposta bruta no caso de um erro HTTP consumindo um serviço SOAP, usando BasicHTTPBinding.

No entanto, ao ler a resposta usando GetResponseStream(), obteve o erro:

Stream não legível

Então, este código funcionou para mim:

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

Você também pode usar esta biblioteca que envolve HttpWebRequest e Response em métodos simples que retornam objetos com base nos resultados. Ele usa algumas das técnicas descritas nessas respostas e tem muito código inspirado nas respostas deste e de tópicos semelhantes. Ele captura automaticamente quaisquer exceções, busca abstrair o máximo possível de código padrão para fazer essas solicitações da web e desserializa automaticamente o objeto de resposta.

Um exemplo de como seu código ficaria usando este wrapper é tão simples quanto

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

    }

Divulgação completa Esta biblioteca é uma biblioteca wrapper de código aberto e gratuita, e eu sou o autor da referida biblioteca. Não ganho dinheiro com isso, mas acho que é imensamente útil ao longo dos anos e tenho certeza de que qualquer pessoa que ainda usa as classes HttpWebRequest / HttpWebResponse também o fará.

Não é uma solução mágica, mas oferece suporte para obter, postar e excluir com async e não async para get e post, bem como solicitações e respostas JSON ou XML. Ele está sendo mantido ativamente a partir de 21/06/2020

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