Как я могу поймать 404?


95

У меня такой код:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "HEAD";
request.Credentials = MyCredentialCache;

try
{
    request.GetResponse();
}
catch
{
}

Как я могу поймать конкретную ошибку 404? WebExceptionStatus.ProtocolError может только определить, что произошла ошибка, но не дать точный код ошибки.

Например:

catch (WebException ex)
{
    if (ex.Status != WebExceptionStatus.ProtocolError)
    {
        throw ex;
    }
}

Просто недостаточно полезно ... исключение протокола может быть 401, 503, 403, действительно что угодно.


13
НННООООООООООООО! Не ловите System.Exceptionи не зависите от текста исключения в вашем обработчике!
Aaronaught

2
Ответ Джона Сондерса был наиболее полным. Я думаю, что люди просто злобно отвергли его.
Aaronaught

3
Не используйте throw ex, вы создадите новое исключение с пустым стеком вызовов. Просто используйте throw.
krbnr

1
Меня всегда это расстраивало. Исключение не должно генерироваться, если вы получили правильно сформированный ответ, а сообщение об ошибке протокола определенно правильно сформировано. Класс должен позволять пользователю интерпретировать результаты и действовать соответственно.
Джереми Головач

Исключения @JeremyHolovacs больше не генерируются для таких вещей, как 404, в новых клиентах http. «Не используйте исключения для потока управления», похоже, не выжило в команде, которая построилаWebRequest
Мэтт Кодж

Ответы:


115

Используйте HttpStatusCode Enumeration, в частностиHttpStatusCode.NotFound

Что-то типа:

HttpWebResponse errorResponse = we.Response as HttpWebResponse;
if (errorResponse.StatusCode == HttpStatusCode.NotFound) {
  //
}

Где
weнаходится WebException.


Могу ли я каким-то образом получить ЧИСЛО из объектов, не создавая свой собственный список поиска? Я хотел бы иметь что-то вроде: int httpresponsecode = HttpStatusCode.ToInt () или аналогичный, поэтому я получаю 404
BerggreenDK

2
@BerggreenDK, вы должны иметь возможность просто сделать int httpresonsecode = (int) HttpStatusCode.NotFound
Trev

8
-1 Частичное объяснение моего давнего отрицательного голоса: код выдает исключение NullReferenceException, если по какой-то причине we.Responseэто не так HttpWebResponse. Если код желает предположить , что она всегда будет иметь этот тип, то он должен просто бросить: HttpWebResponse errorResponse = (HttpWebResponse)we.Response;. Это вызовет явное, InvalidCastExceptionесли произойдет невозможное, вместо загадочного NullReferenceException.
Джон Сондерс

Я An object reference is required for the non-static field, method, or property 'WebException.Response'использую этот код.
Джейми

122
try
{
    var request = WebRequest.Create(uri);
    using (var response = request.GetResponse())
    {
        using (var responseStream = response.GetResponseStream())
        {
            // Process the stream
        }
    }
}
catch (WebException ex)
{
    if (ex.Status == WebExceptionStatus.ProtocolError &&
        ex.Response != null)
    {
        var resp = (HttpWebResponse) ex.Response;
        if (resp.StatusCode == HttpStatusCode.NotFound)
        {
            // Do something
        }
        else
        {
            // Do something else
        }
    }
    else
    {
        // Do something else
    }
}

10
lol @ - это полиция IDisposable и дает всем -1 за то, что ответ не заключен в блок using.
Rich

2
Это тяжелая работа, но кто-то должен ее делать. OTOH, я почти не добавил этот ответ, так как могло показаться, что я уговаривал всех, чтобы мой ответ был самым популярным.
Джон Сондерс

3
Я на самом деле проголосовал за, но только что заметил одну вещь: вероятно, throwв конце вашего должен быть (переброс) catch, иначе он просто незаметно съест любой другой тип WebException.
Aaronaught

@John Saunders: Почему ты тоже не используешь свой запрос?
Джоэл Этертон

1
@Joel: WebRequestне реализует IDisposable.
Джон Сондерс

25

В C # 6 вы можете использовать фильтры исключений .

try
{
    var request = WebRequest.Create(uri);
    using (var response = request.GetResponse())
    using (var responseStream = response.GetResponseStream())
    {
        // Process the stream
    }
}
catch(WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
{
    // handle 404 exceptions
}
catch (WebException ex)
{
    // handle other web exceptions
}

Очень крутая функция, на которую я не обращал внимания! Я продолжал искать методы, позволяющие поймать только 401, позволяя другим проходить через общий обработчик исключений. Это путь!
Lionet Chen

Замечательно, это должен быть принятый ответ.
Lucas925,

12

Я не тестировал это, но он должен работать

try
{
    // TODO: Make request.
}
catch (WebException ex)
{
    if (ex.Status == WebExceptionStatus.ProtocolError) {
        HttpWebResponse resp = ex.Response as HttpWebResponse;
        if (resp != null && resp.StatusCode == HttpStatusCode.NotFound)
        {
            // TODO: Handle 404 error.
        }
        else
            throw;
    }
    else
        throw;
}

@John Saunders - Я адаптировал код OP, а не оптимизировал его.
MiffTheFox

@John - И, возможно, я только ожидал, что они скопируют / вставят catchблок, поскольку у меня был тот же код в попытке, что и OP. Тогда вы действительно должны вообще отказаться от этого вопроса из-за кода OP.
MiffTheFox

1
@John, мы забываем, вот пример кода. Это тот случай, когда это еще один способ получить 404, а не как использовать GetResponse. -1 кажется немного резковатым. +1 Миффу за ответ на вопрос.
Дэвид Басараб

@John Я думаю, это хорошо, что вы указали на это в комментарии. Я смотрю на голосование вниз, если приведенный код не решает проблему. Спасибо, что сняли голос "против".
Дэвид Басараб

@John - Хорошо, я избавился от всего, кроме улова, теперь счастлив?
MiffTheFox

4

Я думаю, что если вы поймаете WebException, там есть некоторая информация, которую вы можете использовать, чтобы определить, было ли это 404. Это единственный способ, о котором я знаю на данный момент ... Мне было бы интересно узнать любые другие ...

catch(WebException e) {
    if(e.Status == WebExceptionStatus.ProtocolError) {
        var statusCode = (HttpWebResponse)e.Response).StatusCode);
        var description = (HttpWebResponse)e.Response).StatusDescription);
    }
}

2

Посмотрите этот снайпер. GetResponse вызовет исключение WebRequestException. Поймайте это, и вы сможете получить код статуса из ответа.

try {
   // Create a web request for an invalid site. Substitute the "invalid site" strong in the Create call with a invalid name.
     HttpWebRequest myHttpWebRequest = (HttpWebRequest) WebRequest.Create("invalid site");

    // Get the associated response for the above request.
     HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
    myHttpWebResponse.Close();
}
catch(WebException e) {
    Console.WriteLine("This program is expected to throw WebException on successful run."+
                        "\n\nException Message :" + e.Message);
    if(e.Status == WebExceptionStatus.ProtocolError) {
        Console.WriteLine("Status Code : {0}", ((HttpWebResponse)e.Response).StatusCode);
        Console.WriteLine("Status Description : {0}", ((HttpWebResponse)e.Response).StatusDescription);
    }
}
catch(Exception e) {
    Console.WriteLine(e.Message);
}

это пришло с http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx


2

Поймать правильный тип исключения WebException:

try
{
    var request = (HttpWebRequest) WebRequest.Create(String.Format("http://www.gravatar.com/avatar/{0}?d=404", hashe));

    using(var response = (HttpWebResponse)request.GetResponse())
        Response.Write("has avatar");
}
catch(WebException e) 
{
  if(e.Response.StatusCode == 404) 
    Response.Write("No avatar");
}

@John Saunders: Я не спорю с вами там, но вопрос был не в этом, он спросил, как лучше всего записать 404. Мои изменения в его коде были ограничены ответом на вопрос, чтобы сделать изменение настолько простым и очевидным, как возможный.
Ник Крейвер

@John Saunders: Исправлено, я полагаю, что «если это наиболее эффективно» применимо к вопросу.
Ник Крейвер

Просто нужно было разыграть e.Responseкак HttpWebResponseдо получения доступа к StatusCode.
Lankymart

2

См. Информацию о статусе ответа в MSDN :

...
catch(WebException e) {
  Console.WriteLine("The following error occured : {0}",e.Status);  
}
...

2
@John Saunders - Я буду более чем счастлив передать его в MSDN (где я скопировал образец из ...). Цель этого кода - показать использование StatusCode, а не быть максимально эффективным.
Dror

2
@John Saunders - Я оставил только ту часть, которую хотел показать, специально для вас :-)
Dror

2

Я считаю, что для людей VB.NET, просматривающих это, мы можем поймать исключение только в том случае, если это действительно 404. Что-то вроде:

Try
    httpWebrequest.GetResponse()
Catch we As WebException When we.Response IsNot Nothing _
                              AndAlso TypeOf we.Response Is HttpWebResponse _
                              AndAlso (DirectCast(we.Response, HttpWebResponse).StatusCode = HttpStatusCode.NotFound)

    ' ...

End Try

1

при отправке данных POST или GET на сервер с использованием класса WebRequest тип исключения будет WebException. Ниже приведен код исключения файла, который не найден.

        //Create a web request with the specified URL
            string path = @"http://localhost/test.xml1";
            WebRequest myWebRequest = WebRequest.Create(path);

       //Senda a web request and wait for response.
                try
                {
                    WebResponse objwebResponse = myWebRequest.GetResponse();
                    Stream stream= objwebResponse.GetResponseStream();

                }
                catch (WebException ex) {
                    if (((HttpWebResponse)(ex.Response)).StatusCode == HttpStatusCode.NotFound) {
                        throw new FileNotFoundException(ex.Message);
                    }

                }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.