.Net HttpWebRequest.GetResponse () levanta exceção quando http código de status 400 (Bad Request) é devolvido

StackOverflow https://stackoverflow.com/questions/692342

  •  22-08-2019
  •  | 
  •  

Pergunta

Eu estou em uma situação onde, quando eu recebo um código HTTP 400 do servidor, é uma maneira completamente legal do servidor me dizer o que estava errado com o meu pedido (através de uma mensagem no conteúdo da resposta HTTP)

No entanto, a NET HttpWebRequest levanta uma exceção quando o código de status é de 400.

Como posso lidar com isso? Para mim um 400 é completamente legal e bastante útil. O conteúdo HTTP tem alguma informação importante, mas a exceção me joga fora de meu caminho.

Foi útil?

Solução

Seria bom se houvesse alguma maneira de desligar "jogar em código não-sucesso", mas se você pegar WebException você pode pelo menos usar a resposta:

using System;
using System.IO;
using System.Web;
using System.Net;

public class Test
{
    static void Main()
    {
        WebRequest request = WebRequest.Create("http://csharpindepth.com/asd");
        try
        {
            using (WebResponse response = request.GetResponse())
            {
                Console.WriteLine("Won't get here");
            }
        }
        catch (WebException e)
        {
            using (WebResponse response = e.Response)
            {
                HttpWebResponse httpResponse = (HttpWebResponse) response;
                Console.WriteLine("Error code: {0}", httpResponse.StatusCode);
                using (Stream data = response.GetResponseStream())
                using (var reader = new StreamReader(data))
                {
                    string text = reader.ReadToEnd();
                    Console.WriteLine(text);
                }
            }
        }
    }
}

Você pode gostar de encapsular o "get me uma resposta, mesmo se não é um código de sucesso" bit em um método separado. (Eu sugiro que você ainda jogar se não houver uma resposta, por exemplo, se você não pôde se conectar.)

Se a resposta de erro pode ser grande (o que é incomum), você pode querer ajustar HttpWebRequest.DefaultMaximumErrorResponseLength para ter certeza de obter toda a erro.

Outras dicas

Eu sei que isso já foi respondido há muito tempo, mas eu fiz um método de extensão para espero ajudar outras pessoas que vêm a esta questão.

Código:

public static class WebRequestExtensions
{
    public static WebResponse GetResponseWithoutException(this WebRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        try
        {
            return request.GetResponse();
        }
        catch (WebException e)
        {
            if (e.Response == null)
            {
                throw;
            }

            return e.Response;
        }
    }
}

Uso:

var request = (HttpWebRequest)WebRequest.CreateHttp("http://invalidurl.com");

//... (initialize more fields)

using (var response = (HttpWebResponse)request.GetResponseWithoutException())
{
    Console.WriteLine("I got Http Status Code: {0}", response.StatusCode);
}

Curiosamente, o HttpWebResponse.GetResponseStream() que você começa a partir do WebException.Response não é o mesmo que o fluxo de resposta que você teria recebido do servidor. Em nosso meio, estamos perdendo respostas do servidor reais quando um 400 status HTTP código é devolvido de volta ao cliente usando os objetos HttpWebRequest/HttpWebResponse. Pelo que vimos, o fluxo de resposta associado ao WebException's HttpWebResponse é gerado no cliente e não inclui qualquer do corpo resposta do servidor. Muito frustrante, pois queremos mensagem de volta ao cliente a razão para o mau pedido.

Eu tive problemas semelhantes ao tentar conectar ao serviço OAuth2 do Google.

acabei escrevendo o POST manualmente, sem usar WebRequest, como este:

TcpClient client = new TcpClient("accounts.google.com", 443);
Stream netStream = client.GetStream();
SslStream sslStream = new SslStream(netStream);
sslStream.AuthenticateAsClient("accounts.google.com");

{
    byte[] contentAsBytes = Encoding.ASCII.GetBytes(content.ToString());

    StringBuilder msg = new StringBuilder();
    msg.AppendLine("POST /o/oauth2/token HTTP/1.1");
    msg.AppendLine("Host: accounts.google.com");
    msg.AppendLine("Content-Type: application/x-www-form-urlencoded");
    msg.AppendLine("Content-Length: " + contentAsBytes.Length.ToString());
    msg.AppendLine("");
    Debug.WriteLine("Request");
    Debug.WriteLine(msg.ToString());
    Debug.WriteLine(content.ToString());

    byte[] headerAsBytes = Encoding.ASCII.GetBytes(msg.ToString());
    sslStream.Write(headerAsBytes);
    sslStream.Write(contentAsBytes);
}

Debug.WriteLine("Response");

StreamReader reader = new StreamReader(sslStream);
while (true)
{  // Print the response line by line to the debug stream for inspection.
    string line = reader.ReadLine();
    if (line == null) break;
    Debug.WriteLine(line);
}

A resposta que obtém escrito para o fluxo de resposta contém o texto de erro específico que você está depois.

Em particular, o meu problema era que eu estava colocando linhas finais entre as peças de dados codificado em URL. Quando assumi-los, tudo funcionou. Você pode ser capaz de usar uma técnica semelhante para se conectar ao seu serviço e ler o texto de erro de resposta real.

Tente este (é VB-Code: -):

Try

Catch exp As WebException
  Dim sResponse As String = New StreamReader(exp.Response.GetResponseStream()).ReadToEnd
End Try

Uma versão assíncrona da função de extensão:

    public static async Task<WebResponse> GetResponseAsyncNoEx(this WebRequest request)
    {
        try
        {
            return await request.GetResponseAsync();
        }
        catch(WebException ex)
        {
            return ex.Response;
        }
    }

Este resolvido para mim:
https://gist.github.com/beccasaurus/929007/a8f820b153a1cfdee3d06a9c0a1d7ebfced8bb77

TL; DR:
Problema:
localhost retornos conteúdo esperado, altera IP remotos 400 conteúdo para "Bad Request"
Solução:
Adicionando <httpErrors existingResponse="PassThrough"></httpErrors> para web.config/configuration/system.webServer resolvido isso por mim; agora todos os servidores (local e remoto) retornam o mesmo conteúdo exato (gerado por mim) independentemente do endereço IP e / ou HTTP código que eu retorno.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top