2009-05-29 45 views
96

Estoy haciendo un programa simple en visual C# 2005 que busca un símbolo de stock en Yahoo! Financie, descarga los datos históricos y luego traza el historial de precios para el símbolo de cotización especificado.C# ¿Cómo puedo verificar si existe una URL/es válida?

Conozco la URL exacta que necesito para adquirir los datos, y si el usuario ingresa un símbolo de cotización existente (o al menos uno con datos en Yahoo! Finanzas) funciona perfectamente bien. Sin embargo, tengo un error de tiempo de ejecución si el usuario crea un símbolo de cotización, ya que el programa intenta extraer datos de una página web inexistente.

Estoy usando la clase WebClient y usando la función DownloadString. Revisé todas las otras funciones miembro de la clase WebClient, pero no vi nada que pudiera usar para probar una URL.

¿Cómo puedo hacer esto?

+1

actualiza para mostrar C# 2.0 (VS2005) el uso –

Respuesta

97

¿Podría emitir una solicitud "HEAD" en lugar de un "OBTENER"?

(corregir) - ¡lol! Parece que tengo done this before!; cambiado a wiki para evitar acusaciones de rep-garnering. Así que para probar una dirección URL sin el coste de la descarga del contenido:

// 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"); 
} 

Usted haría try/catch alrededor del DownloadString para comprobar si hay errores; ¿No hay error? Existe ...


con C# 2.0 (VS2005):

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

y

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

buena idea con el cambio a wiki en estos casos; lo tendremos en cuenta para uso futuro ... –

+0

FWIW - No estoy seguro de si realmente resuelve el problema (aparte de tal vez el comportamiento diferente del lado del cliente) ya que simplemente está cambiando el método HTTP. La respuesta del servidor dependerá en gran medida de cómo se codifique la lógica y puede no funcionar bien para un servicio dinámico como el precio de las acciones. Para los recursos estáticos (por ejemplo, imágenes, archivos, etc.) HEAD generalmente funciona como se anuncia, ya que se hornea en el servidor. Muchos programadores no abordan explícitamente las solicitudes, ya que normalmente se centran en POST y GET. YMMV –

+0

Perdón por tomar tanto tiempo para elegir una respuesta ... Me desvié de la escuela y el trabajo y me olvidé de esta publicación. Como nota al margen, no pude conseguir que tu solución funcione porque estoy usando Visual Studio 2005 que no tiene el tipo 'var'. No he trabajado en este proyecto en meses, pero ¿hay una solución simple para ese hecho? Además, cuando traté de implementar su solución, recuerdo que se enojó conmigo por tratar de definir la propiedad HeadOnly sin código en las definiciones 'get' y 'set'. O tal vez solo estaba haciendo algo mal. ¡Gracias por la ayuda! –

0

servidores Web responde con un código de estado HTTP que indica el resultado de la solicitud, por ejemplo, 200 (a veces 202) significa éxito, 404 - no encontrado, etc. (ver here). Suponiendo que la dirección del servidor parte de la URL es correcta y no está obteniendo un tiempo de espera del socket, la excepción probablemente le indique que el código de estado HTTP no era 200. Sugeriría verificar la clase de la excepción y ver si la excepción conlleva el código de estado HTTP.

IIRC: la llamada en cuestión arroja una WebException o un descendiente. Compruebe el nombre de la clase para ver cuál y envuelva la llamada en un bloque de prueba para atrapar la condición.

+2

En realidad, cualquier cosa en el rango 200-299 significa éxito, IIRC –

+0

Marc, tiene toda la razón. Intencionalmente evité entrar en el concepto de "clase de error" (por ejemplo, 5xx, 4xx, 3xx, 2xx, etc.) ya que eso abre una lata de gusanos entera. Incluso el manejo de los códigos estándar (200, 302, 404, 500, etc.) es mucho mejor que ignorar los códigos por completo. –

7

Si entiendo bien su pregunta, se puede usar un método pequeña como esta para darle los resultados de la prueba 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; 

Se puede envolver el código anterior en un método y utilizarlo para realizar validación. Espero que esto responda la pregunta que estabas haciendo.

+1

Sí, quizás pueda refinar la solución diferenciando entre diferentes casos (falla de conexión TCP - el host rechaza la conexión, 5xx - sucedió algo fatal, 404 - No se encontró el recurso, etc.).Eche un vistazo a la propiedad Estado de WebException;) –

+0

Muy buen punto David! Eso nos daría una retroalimentación más detallada para que podamos manejar el error más astutamente. –

+1

Gracias. Mi punto es que hay varias capas en esta cebolla, cada una de las cuales puede lanzar una llave en las obras (.Net Framework, Resolución de DNS, Conectividad TCP, Servidor web de destino, aplicación de destino, etc.). En mi humilde opinión, un buen diseño debería ser capaz de discriminar entre las diferentes condiciones de falla para proporcionar retroalimentación informativa y diagnósticos utilizables. Tampoco olvidemos que el HTTP tiene códigos de estado por una razón;) –

113

Aquí es otra implementación de esta solución:

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

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

+1

Estoy usando este código para verificar si existe un grupo de imágenes, y es bastante lento (un par de segundos por URL). ¿Alguien sabe si esto es un problema con este código, o simplemente un hecho de la vida al hacer este tipo de llamadas? – ssmith

+2

+1 para el código. Sin embargo, es más legible sin los comentarios, IMO ... –

+1

Me gustó el código: está limpio y funciona estable. – Demir

2

Esta solución parece fácil de seguir:

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

no se olvide de cerrar webResponse, de lo contrario aumentará el tiempo de respuesta cada vez que llame a su método – Madagaga

25

Estas soluciones son bastante buenos, pero están olvidando que puede haber otros códigos de estado que 200 OK.Esta es una solución que he usado en entornos de producción para el monitoreo de estado y demás.

Si hay una redirección url o alguna otra condición en la página de destino, la devolución será verdadera utilizando este método. Además, GetResponse() emitirá una excepción y, por lo tanto, no obtendrá un código de estado para ello. Debe atrapar la excepción y comprobar si hay un error de protocolo.

Cualquier código de estado 400 o 500 devolverá falso. Todos los demás regresan verdad. Este código se modifica fácilmente para adaptarse a sus necesidades de códigos de estado específicos.

/// <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

. Añadiría que algunos códigos de estado en el rango 3xx causarán un error, p. Ej. 304 No modificado, en cuyo caso deberías manejarlo en tu bloque catch – RobV

+3

Acabo de experimentar un problema con este enfoque: 'HttpWebRequest' no le gusta si no lo haces' .Close() ' el objeto 'response' antes de intentar descargar cualquier otra cosa. ¡Tomó horas encontrarlo! – jbeldock

+2

El objeto 'HttpWebResponse' ** debe estar incluido en' using' block ** ya que implementa 'IDisposable' que también asegurará el cierre de la conexión. Esto podría causar problemas ya que @jbeldock se ha enfrentado. – Habib

0

tengo una manera más simple de determinar si una URL es válida.

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

No, este método no verifica si la url es realmente accesible. Incluso devuelve verdadero cuando Uri.IsWellFormedUriString ("http://192.168.1.421/", ...), que utiliza una URL obviamente incorrecta – zhaorufei

2

Aquí es otra opción

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

Eso podría ser útil para comprobar si existe un host. La pregunta obviamente no está preocupada acerca de si el host existe o no. Se trata de manejar una ruta HTTP incorrecta * dado que se sabe que el host existe y está bien *. – binki

0

A raíz de los ejemplos ya dados, yo diría, es la mejor práctica para envolver también la respuesta en un usando como esto

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

Pruebe esto (asegúrese de usar System.Net):

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

Cuando se llama a la función checkWebsite(), intenta obtener el código fuente de donde se pasó la URL. Si obtiene el código fuente, devuelve verdadero. Si no, devuelve falso.

Ejemplo de código:

//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"); 
Cuestiones relacionadas