Як я можу зловити 404?


93

У мене є такий код:

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
Метт Коджай,

Відповіді:


113

Використовуйте 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

7
-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 @, будучи одноразовою поліцією, і дає всім -1 за те, що не загортає відповідь у використовуючий блок.
Rich

2
Це важка робота, але хтось повинен її робити. ОТО, я майже не додав цієї відповіді, оскільки може здатися, що я змушував усіх інших зробити свою відповідь з найвищим рейтингом.
Джон Сондерс,

3
Я насправді проголосував за, але я просто помітив одне: мабуть, має бути throw(перекидання) в кінці вашого catch, інакше це просто мовчки з'їсть будь-який інший тип WebException.
Aaronaught

@ Джон Сондерс: Чому б вам також не використати ваш запит?
Джоел Етертон,

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

23

У 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

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. Тоді вам справді слід було б повністю відмовитись від цього питання через код ОП.
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");
}

@ Джон Сондерс, я там вас не обговорюю, але це не було питання, він попросив найкращий спосіб зафіксувати 404. Мої зміни до його коду обмежувались лише відповіддю на питання, щоб зробити зміну такою ж простою та очевидною, як можливо.
Нік Кравер

@ Джон Сондерс: Виправлено, я думаю, "якщо це найбільш ефективно", це стосується питання.
Нік Кравер

Просто довелося кинути e.Responseяк HttpWebResponseраніше, ніж отримати доступ до StatusCode.
Lankymart

2

Дивіться на MSDN про стан відповіді:

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

2
@John Saunders - Я з великим задоволенням передам його MSDN (де я скопіював зразок з ...). Мета цього коду - показати використання StatusCode, а не бути максимально ефективним.
Дрор

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

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.