HttpWebRequest.GetResponse выдает WebException на HTTP 304

Когда веб-сервер отвечает на HttpWebRequest.GetResponse() HTTP 304 (не изменено), GetResponse() выдает WebException, что для меня очень странно. Это по дизайну или я упустил что-то очевидное здесь?


person Anton Gogolev    schedule 02.09.2009    source источник


Ответы (5)


Хорошо, похоже, это поведение по дизайну и прекрасный пример досадное исключение. Это можно решить с помощью этого:

public static HttpWebResponse GetHttpResponse(this HttpWebRequest request)
{
    try
    {
        return (HttpWebResponse) request.GetResponse();
    }
    catch (WebException ex)
    {
        if(ex.Response == null || ex.Status != WebExceptionStatus.ProtocolError)
            throw; 

        return (HttpWebResponse)ex.Response;
    }
}
person Anton Gogolev    schedule 02.09.2009
comment
Это работает в большинстве случаев, но некоторые веб-серверы могут возвращать тело ответа при возврате ошибки 404. В этом случае приведенный выше код будет обрабатывать 404 так же, как и 304! - person comshak; 07.01.2010
comment
@comshak это полезно знать. Вызывающий код должен знать, какие коды ответа являются приемлемыми. - person roufamatic; 07.07.2011
comment
Я также добавил || ((HttpWebResponse) ex.Response).StatusCode != HttpStatusCode.NotModified - person Danny Beckett; 25.11.2013
comment
Вы должны обновить это, чтобы использовать предложение when C#-6.0! - person binki; 06.01.2016
comment
В качестве бонуса раньше можно было декорировать метод с помощью [DebuggerNonUserCode], и ​​отладчик не останавливался в этом методе при возникновении исключения. Таким образом, плохо спроектированные исключения можно завернуть и проигнорировать. Но теперь требуется настройка реестра - person crokusek; 11.10.2017

Это действительно неприятная проблема, и в качестве альтернативы ее можно обойти, используя следующий класс метода расширения и вызвав request.BetterGetResponse().

//-----------------------------------------------------------------------
//
//     Copyright (c) 2011 Garrett Serack. All rights reserved.
//
//
//     The software is licensed under the Apache 2.0 License (the "License")
//     You may not use the software except in compliance with the License.
//
//-----------------------------------------------------------------------

namespace CoApp.Toolkit.Extensions {
    using System;
    using System.Net;

    public static class WebRequestExtensions {
        public static WebResponse BetterEndGetResponse(this WebRequest request, IAsyncResult asyncResult) {
            try {
                return request.EndGetResponse(asyncResult);
            }
            catch (WebException wex) {
                if( wex.Response != null ) {
                    return wex.Response;
                }
                throw;
            }
        }

        public static WebResponse BetterGetResponse(this WebRequest request) {
            try {
                return request.GetResponse();
            }
            catch (WebException wex) {
                if( wex.Response != null ) {
                    return wex.Response;
                }
                throw;
            }
        }
    }
}

Подробнее об этом читайте в моем блоге на эту тему по адресу http://fearthecowboy.com/2011/09/02/fixing-webrequests-desire-to-throw-exceptions-instead-of-returning-статус/

person Garrett Serack    schedule 03.09.2011

Чтобы избежать этого System.WebException, нужно установить AllowAutoRedirect на false. Это отключает логику автоматического перенаправления файла WebRequest. Кажется, он сломан для 304 запросов перенаправления, так как это не настоящее перенаправление в самом строгом смысле. Конечно, это означает, что другие запросы перенаправления 3xx должны обрабатываться вручную.

person Sebastian    schedule 18.12.2013
comment
Абсолютно блестящий. Почему я должен платить за неуклюжий механизм исключений, если он мне не нужен? - person jsuddsjr; 03.11.2017

Как и для вашего сведения, это обновление ответа Антона Гоголева, в котором используется предложение C#6 (VS2015) when. Это немного менее раздражает при использовании отладчика, поскольку он удаляет одну точку перехвата:

public static HttpWebResponse GetHttpResponse(this HttpWebRequest request)
{
    try
    {
        return (HttpWebResponse) request.GetResponse();
    }
    catch (WebException ex)
        when (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
    {
        return (HttpWebResponse) ex.Response;
    }
}
person Community    schedule 08.08.2017

Я также столкнулся с этой проблемой с кодом:

try
{
    ...
    var webResponse = req.GetResponse();
    ...
}
catch (WebException ex)
{
    Log.Error("Unknown error occured", ex);
    //throw; 
}

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

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

try
{
    ...
    var webResponse = req.GetResponse();
    ...
}
catch (WebException ex)
{
    if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotModified)
        throw;
    Log.Error("Unknown error occured", ex);
}
person Ingenium    schedule 08.06.2016