Как получить информацию об ошибке при сбое HttpWebRequest.GetResponse ()

86

Я инициирую HttpWebRequest, а затем получаю его ответ. Иногда я получаю ошибку 500 (или как минимум 5 ##), но без описания. Я контролирую обе конечные точки и хочу, чтобы получающая сторона получила немного больше информации. Например, я хотел бы передать сообщение об исключении с сервера клиенту. Возможно ли это с помощью HttpWebRequest и HttpWebResponse?

Код:

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

Любая помощь с этим будет очень признательна.

Тревор
источник

Ответы:

151

Возможно ли это с помощью HttpWebRequest и HttpWebResponse?

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

Таким образом, вы можете поймать WebException, который будет выдан, если с сервера будет возвращен код состояния, отличный от 200, и прочитать его тело:

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
}
Дарин Димитров
источник
Спасибо! Важно отметить, что поток внутри оператора using не будет доступен за пределами оператора using, поскольку средство удаления WebResponse очистит его. Это сбило меня с толку на несколько минут.
Thorin
@ Торин. «Поток» от первого оператора переходит к следующему оператору. Так же, как в однострочном операторе IF, например, if (something) do-stuff-here;
RealityDysfunction
1
GetRequestStreamа GetResponseможет кидать исключения ?
PreguntonCojoneroCabrón
@ PreguntonCojoneroCabrón Да, кажется, это не совсем так, правда? К счастью, Microsoft представила класс HttpClient, который, как я подозреваю, в настоящее время используется больше всего. msdn.microsoft.com/en-us/library/…
Мортен
8

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

ResponseСобственности на WebExceptionбудет иметь тип , FtpWebResponseна котором вы можете проверить его StatusCodeсвойства , чтобы увидеть , который FTP ошибка у вас есть.

Вот код, который у меня получился:

    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
источник
4

Я столкнулся с похожей ситуацией:

Я пытался прочитать необработанный ответ в случае ошибки HTTP, использующей службу SOAP, используя BasicHTTPBinding.

Однако при чтении ответа с помощью GetResponseStream()получил ошибку:

Поток не читается

Итак, у меня сработал этот код:

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();
}
Жоао Паулу Мело
источник
0

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

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

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

    }

Полное раскрытие информации Эта библиотека является бесплатной библиотекой-оболочкой с открытым исходным кодом, и я являюсь автором указанной библиотеки. Я не зарабатываю на этом денег, но на протяжении многих лет считаю его чрезвычайно полезным, и уверен, что любой, кто все еще использует классы HttpWebRequest / HttpWebResponse, тоже будет.

Это не серебряная пуля, но поддерживает получение, публикацию, удаление как с асинхронным, так и без асинхронного режима для получения и публикации, а также для запросов и ответов JSON или XML. Активно поддерживается по состоянию на 21.06.2020

pat8719
источник
-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(); 
Пранеш Джанартанан
источник