2011-05-06 28 views
43

¿Cómo podría verificar si existe una URL con Ruby?Comprobar si existe una URL en Ruby

Por ejemplo, para la dirección URL

https://google.com 

el resultado debería ser Truthy, pero para los URLs

https://no.such.domain 

o

https://stackoverflow.com/no/such/path 

el resultado debería ser Falsey

+3

pregunta era lo suficientemente bueno para que coincida con mi búsqueda de google y respuestas son valiosas – kranzky

+0

estoy de acuerdo. Esta pregunta es útil. –

+0

Creo que esta es una buena pregunta con respuestas útiles. La razón por la que fue cerrada ("debe demostrar una comprensión mínima") ya no es válida en SO. He editado la pregunta para agregar algunos ejemplos. Con eso, creo que la pregunta puede ser reabierta ahora. –

Respuesta

55

Uso de la biblioteca Net::HTTP.

require "net/http" 
url = URI.parse("http://www.google.com/") 
req = Net::HTTP.new(url.host, url.port) 
res = req.request_head(url.path) 

En este punto res es un objeto Net::HTTPResponse que contiene el resultado de la solicitud. A continuación, puede comprobar el código de respuesta:

do_something_with_it(url) if res.code == "200" 

Nota: Para comprobar si hay https url basada, use_ssl atributo debe ser true como:

require "net/http" 
url = URI.parse("https://www.google.com/") 
req = Net::HTTP.new(url.host, url.port) 
req.use_ssl = true 
res = req.request_head(url.path) 
+3

¿Qué hay de las redirecciones? 302 código http –

+0

en la producción, para todos y cada URL que esto me está volviendo código 200 .. i han analizado '' 'http: //www.http: /' '' esta URL y me dio 200 OK ... pero que está mal ... ¿Cuál es el problema aquí? ¿Alguna idea? Nota: Esto funciona bien en Env Local. –

3

de respuesta Simone fue muy útil para mí.

Aquí es una versión que devuelve verdadero/falso dependiendo de validez URL, y que maneja las redirecciones:

require 'net/http' 
require 'set' 

def working_url?(url, max_redirects=6) 
    response = nil 
    seen = Set.new 
    loop do 
    url = URI.parse(url) 
    break if seen.include? url.to_s 
    break if seen.size > max_redirects 
    seen.add(url.to_s) 
    response = Net::HTTP.new(url.host, url.port).request_head(url.path) 
    if response.kind_of?(Net::HTTPRedirection) 
     url = response['location'] 
    else 
     break 
    end 
    end 
    response.kind_of?(Net::HTTPSuccess) && url.to_s 
end 
+0

¿Qué sucede si el servidor no es compatible con las solicitudes HEAD? –

20

Net::HTTP obras pero si se puede trabajar stdlib exterior, Faraday es mejor.

Faraday.head(the_url).status == 200 

(200 es un código de éxito, suponiendo que eso es lo que entiende por "existe".)

+1

¿Por qué es mejor en tu opinión? – Dennis

+2

También puede usar la [Biblioteca de RestClient] (https://github.com/rest-client/rest-client). 'require 'rest_client'; RestClient.head (url) .code! = 404' – Dennis

43

Lo siento por la respuesta tardía en esto, pero creo que este deservers una mejor respuesta.

Hay tres maneras de ver esta pregunta:

  1. control estricto si la URL existe
  2. Comprobar si está solicitando el correclty URL
  3. Comprobar si se puede solicitar de manera correcta y el servidor puede responder correctamente

1. estricto control si existe la URL

Mientras que 200 significa que el servidor responde a esa URL (por lo tanto, la URL existe), responder a otro código de estado no significa que la URL no existe. Por ejemplo, al responder 302 - redirected, significa que la URL existe y está redireccionando a otra.Durante la navegación, 302 muchas veces se comporta igual que 200 para el usuario final. Otro código de estado que se puede devolver si existe una URL es 500 - internal server error. Después de todo, si la URL no existe, ¿cómo es que el servidor de aplicaciones procesó su solicitud en su lugar devuelve simplemente 404 - not found?

Así que en realidad sólo hay uno dos casos en los que no existe una URL: Cuando el servidor no existe o cuando existe el servidor, pero no puede encontrar la ruta URL dado no existe. Por lo tanto, la única manera de comprobar si existe la URL está comprobando si el servidor responde y el código de retorno no es 404. El siguiente código hace exactamente eso.

require "net/http" 
def url_exist?(url_string) 
    url = URI.parse(url_string) 
    req = Net::HTTP.new(url.host, url.port) 
    req.use_ssl = (url.scheme == 'https') 
    path = url.path if url.path.present? 
    res = req.request_head(path || '/') 
    res.code != "404" # false if returns 404 - not found 
rescue Errno::ENOENT 
    false # false if can't find the server 
end 

2. Comprobar si está solicitando la URL correclty

Sin embargo, mayoría de las veces no estamos interesados ​​en ver si existe una dirección URL, pero si podemos acceder a él. Afortunadamente mirando a las familias HTTP status codes, que es la familia 4xx, que establece por error del cliente (por lo tanto, un error en su lado, lo que significa que no está solicitando la página correctamente, no tienen permiso o en absoluto). Esta es una buena cantidad de errores para verificar si puede acceder a esta página. De wiki:

The 4xx class of status code is intended for cases in which the client seems to have erred. Except when responding to a HEAD request, the server should include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method. User agents should display any included entity to the user.

Así que el código siguiente Asegúrese de que existe la URL y se puede acceder a él:

require "net/http" 
def url_exist?(url_string) 
    url = URI.parse(url_string) 
    req = Net::HTTP.new(url.host, url.port) 
    req.use_ssl = (url.scheme == 'https') 
    path = url.path if url.path.present? 
    res = req.request_head(path || '/') 
    if res.kind_of?(Net::HTTPRedirection) 
    url_exist?(res['location']) # Go after any redirect and make sure you can access the redirected URL 
    else 
    res.code[0] != "4" #false if http code starts with 4 - error on your side. 
    end 
rescue Errno::ENOENT 
    false #false if can't find the server 
end 

3. Comprobar si se puede solicitar de manera correcta y el servidor puede responder correctamente

Al igual que la familia 4xx comprueba si puede acceder a la URL, la familia 5xx comprueba si el servidor tuvo algún problema para responder a su solicitud. Un error en esta familia la mayoría de las veces se debe a problemas en el servidor, y con suerte están trabajando para resolverlo. Si Tienes que ser capaz de acceder a la página y obtener una respuesta correcta ahora, usted debe asegurarse de que la respuesta no es de 4xx o 5xx familia, y si se redirigió, las respuestas a páginas redirigidas correctamente. Tanto es similar a (2), sólo tiene que utilizar el siguiente código:

require "net/http" 
def url_exist?(url_string) 
    url = URI.parse(url_string) 
    req = Net::HTTP.new(url.host, url.port) 
    req.use_ssl = (url.scheme == 'https') 
    path = url.path if url.path.present? 
    res = req.request_head(path || '/') 
    if res.kind_of?(Net::HTTPRedirection) 
    url_exist?(res['location']) # Go after any redirect and make sure you can access the redirected URL 
    else 
    ! %W(4 5).include?(res.code[0]) # Not from 4xx or 5xx families 
    end 
rescue Errno::ENOENT 
    false #false if can't find the server 
end 
+1

si hace esto con https-urls, es posible que obtenga un error 'Net :: HTTPBadResponse: wrong status line'. Esto se debe a que debes decirle a Net: HTTP que use ssl. Para hacer que funcione también para https, ponga una línea 'req.use_ssl = (url.esquema == 'https') 'antes de llamar a' request_head' –

+0

@YoLudke Gracias por la contribución – fotanus

+1

Otra cosa: si usted solicita (o una redirección es) 'http://www.example.com' (sin seguimiento)/'), entonces obtienes un 'ArgumentError: la ruta de solicitud HTTP está vacía'. Esto puede abordarse cambiando la línea 'res = req.request_head (url.path)' a 'path = url.path si url.path.present?' Y 'req.request_head (path || '/')' –

Cuestiones relacionadas