2009-05-29 21 views
96

Robię prosty program w wizualnym C# 2005, który wyszukuje symbol giełdowy na Yahoo! Finanse, pobiera dane historyczne, a następnie tworzy historię cen dla określonego symbolu giełdowego.C# Jak mogę sprawdzić, czy URL istnieje/jest ważny?

Znam dokładny adres URL, który potrzebuję do pozyskania danych, a jeśli użytkownik wprowadzi istniejący symbol tickera (lub przynajmniej jeden z danymi na Yahoo! Finance), to działa doskonale. Mam jednak błąd wykonania, jeśli użytkownik tworzy symbol tickera, ponieważ program próbuje pobrać dane z nieistniejącej strony internetowej.

Używam klasy WebClient i korzystam z funkcji DownloadString. Przejrzałem wszystkie inne funkcje składowe klasy WebClient, ale nie widziałem niczego, co mógłbym wykorzystać do przetestowania adresu URL.

Jak mogę to zrobić?

+1

zaktualizowana, aby pokazać C# 2.0 (VS2005) Wykorzystanie –

Odpowiedz

97

Możesz wysłać prośbę o numer "HEAD" zamiast "GET"?

(edycja) - lol! Wygląda na to, że mam done this before! zmieniono na wiki, aby uniknąć oskarżeń o rep-garnering. Tak, aby przetestować URL bez kosztów pobierania zawartości:

// using MyClient from linked post 
using(var client = new MyClient()) { 
    client.HeadOnly = true; 
    // fine, no content downloaded 
    string s1 = client.DownloadString("http://google.com"); 
    // throws 404 
    string s2 = client.DownloadString("http://google.com/silly"); 
} 

byś try/catch wokół DownloadString aby sprawdzić błędy; żaden błąd? Istnieje ...


z C# 2.0 (VS2005):

private bool headOnly; 
public bool HeadOnly { 
    get {return headOnly;} 
    set {headOnly = value;} 
} 

i

using(WebClient client = new MyClient()) 
{ 
    // code as before 
} 
+0

Dobry pomysł z włączeniem do wiki w tych sprawach; będę o tym pamiętał do przyszłego użytku ... –

+0

FWIW - Nie jestem pewien, czy to naprawdę rozwiązuje problem (inny niż może inne zachowanie klienta), ponieważ po prostu zmieniasz metodę HTTP. Odpowiedź serwera zależy w dużym stopniu od sposobu kodowania logiki i może nie działać dobrze w przypadku usługi dynamicznej, takiej jak cena akcji. W przypadku zasobów statycznych (np. Obrazów, plików itp.) HEAD zwykle działa tak, jak reklamowano, ponieważ jest wypiekany na serwerze. Wielu programistów nie jawnie żąda HEAD, ponieważ zwykle koncentruje się na POST i GET. YMMV –

+0

Przepraszamy za tak długi czas, aby wybrać odpowiedź ... Odwróciłem się od szkoły i pracy i trochę zapomniałem o tym poście. Jako sidenote, nie mogłem znaleźć rozwiązania, ponieważ używam programu Visual Studio 2005, który nie ma typu "var". Nie pracowałem nad tym projektem od miesięcy, ale czy istnieje prosta poprawka tego faktu? Również kiedy próbowałem wdrożyć twoje rozwiązanie, pamiętam, że wpadło mi we wściekłość za próbę zdefiniowania właściwości HeadOnly bez kodu w definicjach "get" i "ustaw". A może właśnie robiłem coś złego. Dzięki za pomoc! –

0

serwery WWW reagować z kodem stanu HTTP wskazującego na wynik żądanie np 200 (czasami 202) oznacza sukces, 404 - nie znaleziono itd. (Patrz here). Zakładając, że część adresu URL serwera jest poprawna i nie otrzymujesz limitu czasu gniazda, wyjątek najprawdopodobniej mówi ci, że kod statusu HTTP był inny niż 200. Sugerowałbym sprawdzenie klasy wyjątku i sprawdzenie, czy wyjątek niesie kod statusu HTTP.

IIRC - Wezwanie to rzuca wyjątek WebException lub potomek. Sprawdź nazwę klasy, aby zobaczyć, która z nich i zawiń połączenie w bloku try, aby uwięzić ten warunek.

+2

W rzeczywistości wszystko w zakresie 200-299 oznacza sukces, IIRC –

+0

Marc, absolutnie masz rację. Celowo uniknąłem pojęcia "klasy błędu" (np. 5xx, 4xx, 3xx, 2xx itd.), Ponieważ otwiera to zupełnie inną puszkę robaków. Nawet obsługa standardowych kodów (200, 302, 404, 500 itd.) Jest znacznie lepsza niż całkowite zignorowanie kodów. –

7

Jeśli dobrze rozumiem Twoje pytanie, można użyć małego metody tak, aby dać Ci wyniki testu URL:

WebRequest webRequest = WebRequest.Create(url); 
WebResponse webResponse; 
try 
{ 
    webResponse = webRequest.GetResponse(); 
} 
catch //If exception thrown then couldn't get response from address 
{ 
    return 0; 
} 
return 1; 

Można owinąć powyższy kod w metodzie i używać go do wykonywania uprawomocnienie. Mam nadzieję, że to odpowiada na pytanie, które zadawałeś.

+1

Tak, być może możesz udoskonalić rozwiązanie, rozróżniając różne przypadki (błąd połączenia TCP - host odmawia połączenia, 5xx - Coś śmiertelnego się stało, 404 - Nie znaleziono zasobu itp.).Spójrz na właściwość Status WebException;) –

+0

Bardzo dobry punkt David! To dałoby nam bardziej szczegółową informację zwrotną, dzięki czemu moglibyśmy lepiej poradzić sobie z błędem. –

+1

Dzięki. Chodzi mi o to, że do tej cebuli jest kilka warstw, z których każda może rzucić klucz do prac (.Net Framework, DNS Resolution, TCP Connectivity, docelowy serwer sieciowy, aplikacja docelowa itp.). IMHO dobry projekt powinien być w stanie rozróżnić różne warunki awaryjne, aby zapewnić informacje zwrotne i użyteczną diagnostykę. Nie zapominajmy również, że kod HTTP ma przyczynę;) –

113

Oto kolejna realizacja tego rozwiązania:

using System.Net; 

/// 
/// Checks the file exists or not. 
/// 
/// The URL of the remote file. 
/// True : If the file exits, False if file not exists 
private bool RemoteFileExists(string url) 
{ 
    try 
    { 
     //Creating the HttpWebRequest 
     HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; 
     //Setting the Request method HEAD, you can also use GET too. 
     request.Method = "HEAD"; 
     //Getting the Web Response. 
     HttpWebResponse response = request.GetResponse() as HttpWebResponse; 
     //Returns TRUE if the Status code == 200 
     response.Close(); 
     return (response.StatusCode == HttpStatusCode.OK); 
    } 
    catch 
    { 
     //Any exception will returns false. 
     return false; 
    } 
} 

Od: http://www.dotnetthoughts.net/2009/10/14/how-to-check-remote-file-exists-using-c/

+1

Używam tego kodu, aby sprawdzić, czy istnieje kilka obrazów, i jest dość wolny (kilka sekund na adres URL). Czy ktoś wie, czy jest to problem z tym kodem, czy po prostu faktem podczas wykonywania tego rodzaju połączeń? – ssmith

+2

+1 dla kodu. Jest bardziej czytelny bez komentarzy, IMO ... –

+1

Podobał mi się kod: jest czysty i działa stabilnie. – Demir

2

To rozwiązanie wydaje się łatwy do naśladowania:

public static bool isValidURL(string url) { 
    WebRequest webRequest = WebRequest.Create(url); 
    WebResponse webResponse; 
    try 
    { 
     webResponse = webRequest.GetResponse(); 
    } 
    catch //If exception thrown then couldn't get response from address 
    { 
     return false ; 
    } 
    return true ; 
} 
+1

nie zapomnij zamknąć webResponse, w przeciwnym razie czas reakcji wzrośnie za każdym razem, gdy wywołasz twoją metodę. – Madagaga

25

Rozwiązania te są dość dobre, ale oni zapominają że mogą być inne kody stanu niż 200 OK.Jest to rozwiązanie, które stosowałem w środowiskach produkcyjnych do monitorowania statusu i takie.

Jeśli na stronie docelowej znajduje się przekierowanie adresu URL lub jakiś inny warunek, ten zwrot będzie prawdziwy przy użyciu tej metody. Ponadto GetResponse() rzuci wyjątek, a więc nie otrzymasz dla niego kodu stanu. Musisz przechwycić wyjątek i sprawdzić wyjątek ProtocolError.

Każdy kod statusu 400 lub 500 zwróci wartość false. Wszystkie pozostałe zwracają prawdę. Ten kod można łatwo zmodyfikować, aby odpowiadał Twoim potrzebom w zakresie określonych kodów statusu.

/// <summary> 
/// This method will check a url to see that it does not return server or protocol errors 
/// </summary> 
/// <param name="url">The path to check</param> 
/// <returns></returns> 
public bool UrlIsValid(string url) 
{ 
    try 
    { 
     HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest; 
     request.Timeout = 5000; //set the timeout to 5 seconds to keep the user from waiting too long for the page to load 
     request.Method = "HEAD"; //Get only the header information -- no need to download any content 

     HttpWebResponse response = request.GetResponse() as HttpWebResponse; 

     int statusCode = (int)response.StatusCode; 
     if (statusCode >= 100 && statusCode < 400) //Good requests 
     { 
      return true; 
     } 
     else if (statusCode >= 500 && statusCode <= 510) //Server Errors 
     { 
      log.Warn(String.Format("The remote server has thrown an internal error. Url is not valid: {0}", url)); 
      return false; 
     } 
    } 
    catch (WebException ex) 
    { 
     if (ex.Status == WebExceptionStatus.ProtocolError) //400 errors 
     { 
      return false; 
     } 
     else 
     { 
      log.Warn(String.Format("Unhandled status [{0}] returned for url: {1}", ex.Status, url), ex); 
     } 
    } 
    catch (Exception ex) 
    { 
     log.Error(String.Format("Could not test url {0}.", url), ex); 
    } 
    return false; 
} 
+1

Dodam, że niektóre kody stanu w zakresie 3xx rzeczywiście powodują błąd, np. 304 Not Modified, w którym to przypadku powinieneś radzić sobie z tym w swoim bloku catch – RobV

+3

Po prostu doświadczyłeś problemu z wyciąganiem włosów z tego podejścia: 'HttpWebRequest' nie podoba się, jeśli nie używasz' .Close() ' obiekt 'response' przed próbą pobrania czegokolwiek innego. Zajęło to kilka godzin, aby to znaleźć! – jbeldock

+2

'Obiekt HttpWebResponse' ** powinien być ujęty w' using' blok **, ponieważ implementuje 'IDisposable', który również zapewnia zamknięcie połączenia. Może to powodować problemy, na które napotkał @jbeldock. – Habib

0

Mam prostszy sposób na określenie pogody, czy adres URL jest prawidłowy.

if (Uri.IsWellFormedUriString(uriString, UriKind.RelativeOrAbsolute)) 
{ 
    //... 
} 
+3

Nie, ta metoda nie sprawdza, czy adres URL jest naprawdę dostępny. Zwraca także wartość true, gdy Uri.IsWellFormedUriString ("http://192.168.1.421/", ...) używają oczywiście niepoprawnego adresu URL. – zhaorufei

2

Oto kolejna opcja

public static bool UrlIsValid(string url) 
{ 
    bool br = false; 
    try { 
     IPHostEntry ipHost = Dns.Resolve(url); 
     br = true; 
    } 
    catch (SocketException se) { 
     br = false; 
    } 
    return br; 
} 
+2

Może to być przydatne do sprawdzenia, czy host istnieje. Pytanie oczywiście nie martwi się, czy host istnieje. Zajmuje się obsługą złej ścieżki HTTP *, o ile wiadomo, że host istnieje i jest w porządku *. – binki

0

Opierając się na przykładach podanych już, powiedziałbym, to najlepszym rozwiązaniem jest również owinąć odpowiedzi w użyciu jak to

public bool IsValidUrl(string url) 
    { 
     try 
     { 
      var request = WebRequest.Create(url); 
      request.Timeout = 5000; 
      request.Method = "HEAD"; 

      using (var response = (HttpWebResponse)request.GetResponse()) 
      { 
       response.Close(); 
       return response.StatusCode == HttpStatusCode.OK; 
      } 
     } 
     catch (Exception exception) 
     { 
      return false; 
     } 
    } 
2

Spróbuj tego (upewnij się, że używasz System.Net):

public bool checkWebsite(string URL) { 
    try { 
     WebClient wc = new WebClient(); 
     string HTMLSource = wc.DownloadString(URL); 
     return true; 
    } 
    catch (Exception) { 
     return false; 
    } 
} 

Po wywołaniu funkcji checkWebsite() próbuje uzyskać kod źródłowy z przekazanego adresu URL. Jeśli otrzyma kod źródłowy, zwróci true. Jeśli nie, zwraca wartość false.

Kod Przykład:

//The checkWebsite command will return true: 
bool websiteExists = this.checkWebsite("https://www.google.com"); 

//The checkWebsite command will return false: 
bool websiteExists = this.checkWebsite("https://www.thisisnotarealwebsite.com/fakepage.html"); 
Powiązane problemy