.Net HttpWebRequest.GetResponse () вызывает исключение при возврате кода состояния http 400 (неверный запрос) - PullRequest
194 голосов
/ 28 марта 2009

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

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

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

Ответы [ 6 ]

329 голосов
/ 28 марта 2009

Было бы неплохо, если бы был какой-то способ отключить «бросить на неуспешный код», но если вы перехватили 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, чтобы убедиться, что вы получите полную ошибку.

45 голосов
/ 17 января 2013

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

Код:

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);
}
12 голосов
/ 20 апреля 2010

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

11 голосов
/ 20 июля 2011

У меня были похожие проблемы при попытке подключиться к сервису 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 голосов
/ 25 марта 2014

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

Try

Catch exp As WebException
  Dim sResponse As String = New StreamReader(exp.Response.GetResponseStream()).ReadToEnd
End Try
3 голосов
/ 10 февраля 2015

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

    public static async Task<WebResponse> GetResponseAsyncNoEx(this WebRequest request)
    {
        try
        {
            return await request.GetResponseAsync();
        }
        catch(WebException ex)
        {
            return ex.Response;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...