.Net HttpWebRequest.GetResponse() вызывает исключение, когда возвращается код состояния http 400 (неудачный запрос)

Я в ситуации, когда я получаю код HTTP 400 с сервера, это совершенно законный способ сервера, рассказывающий мне, что не так с моим запросом (с использованием сообщения в HTTP-ответе)

Однако .NET HttpWebRequest вызывает исключение, когда код состояния 400.

Как я могу справиться с этим? Для меня 400 совершенно законно и весьма полезно. Содержимое HTTP содержит важную информацию, но исключение меня отключает.

Ответ 1

Было бы неплохо, если бы какой-то способ отключить "бросить код неуспеха", но если вы поймаете WebException, вы можете хотя бы использовать ответ:

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

Вам может потребоваться инкапсулировать бит "получить мне ответ, даже если он не удался" в отдельном методе. (Я бы предположил, что вы все еще бросаете, если нет ответа, например, если вы не можете подключиться.)

Если ответ об ошибке может быть большим (что необычно), вы можете настроить HttpWebRequest.DefaultMaximumErrorResponseLength, чтобы убедиться, что вы получите всю ошибку.

Ответ 2

Я знаю, что это уже давно ответили, но я сделал метод расширения, чтобы надеяться помочь другим людям, которые приходят к этому вопросу.

Код:

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

Применение:

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

Ответ 3

Интересно, что HttpWebResponse.GetResponseStream() который вы получаете из WebException.Response, не совпадает с потоком ответа, который вы получили от сервера. В нашей среде мы теряем фактические ответы сервера, когда код статуса HTTP HTTP возвращается обратно клиенту с использованием объектов HttpWebRequest/HttpWebResponse. Из того, что мы видели, поток ответов, связанный с WebException HttpWebResponse, генерируется на клиенте и не включает какой-либо орган ответа с сервера. Очень расстраивает, так как мы хотим сообщить клиенту причину плохого запроса.

Ответ 4

У меня были подобные проблемы при попытке подключиться к сервису Google OAuth2.

Я закончил писать POST вручную, не используя WebRequest, например:

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

Ответ, который записывается в поток ответов, содержит конкретный текст ошибки, который вы после.

В частности, моя проблема заключалась в том, что я помещал концы между фрагментами данных, закодированными по URL-адресу. Когда я их вытащил, все сработало. Возможно, вы сможете использовать подобный метод для подключения к вашей службе и прочитать фактический текст ошибки ответа.

Ответ 5

Попробуйте это (это VB-код :-):

Try

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

Ответ 6

Асинхронная версия функции расширения:

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

Ответ 7

Я столкнулся с подобной проблемой некоторое время назад. После отладки моего кода я узнал, что транзакция, которую я делал, была логически неправильной. промежуточный итог был равен 0,25 доллара, а сервер PayPal увидел его и отказался обрабатывать его, и дал мне 400 плохих запросов

Ответ 8

Это решило это для меня:
https://gist.github.com/beccasaurus/929007/a8f820b153a1cfdee3d06a9c0a1d7ebfced8bb77

TL; DR:
Проблема:
localhost возвращает ожидаемое содержимое, удаленный IP-адрес изменяет содержимое 400 на "Bad Request"
Решение:
Добавление <httpErrors existingResponse="PassThrough"></httpErrors> в web.config/configuration/system.webServer решило эту проблему для меня; теперь все серверы (локальные и удаленные) возвращают один и тот же контент (созданный мной) независимо от того, какой IP-адрес и/или HTTP-код я возвращаю.