检查URL是否存在于Ruby中

我将如何去检查是否存在使用Ruby的URL?

例如,对于URL

https://google.com 

结果应该是truthy ,但对于URL

 https://no.such.domain 

要么

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

结果应该是错误的

使用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) 

此时res是包含请求结果的Net :: HTTPResponse对象。 然后你可以检查响应码:

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

注意 :要检查基于https的url, use_ssl属性应该为true如下所示:

 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) 

对不起,这个迟到的答复,但我认为这是一个更好的答案。

有三种方法来看这个问题:

  1. 严格检查URL是否存在
  2. 检查您是否正在请求URL correclty
  3. 检查是否可以正确请求,服务器可以正确回答

1.严格检查URL是否存在

200意味着服务器回答该URL(因此,该URL存在),回答其他状态代码并不意味着该URL不存在。 例如,回答302 - redirected意味着该URL存在并正在redirect到另一个。 在浏览的同时,对于最终用户来说, 302多次的performance与200相同。 如果URL存在,可以返回的其他状态代码是500 - internal server error 。 毕竟,如果URL不存在,那么应用程序服务器如何处理您的请求,而不是返回404 - not found

所以当URL不存在时,实际上只有两种情况:当服务器不存在或服务器存在时,但找不到给定的URLpath不存在。 因此,检查URL是否存在的唯一方法是检查服务器是否应答,返回代码是否不是404.下面的代码就是这样做的。

 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.检查您是否正在请求URL correclty

但是, 大多数情况下我们并不感兴趣,看看是否存在一个URL,但如果我们可以访问它 。 幸运的是,查看HTTP状态代码系列,即4xx系列,其中声明客户端错误(因此,在您身边的错误,这意味着您没有正确请求页面,没有任何权限或任何)。 这是一个很好的错误,以检查您是否可以访问此页面。 从wiki:

4xx类状态码用于客户端似乎有错误的情况。 除了响应HEAD请求之外,服务器应该包含一个包含错误情况解释的实体,以及它是临时还是永久状态。 这些状态码适用于任何请求方法。 用户代理应该向用户显示任何包含的实体。

所以下面的代码确保URL存在,你可以访问它

 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.检查是否可以正确请求,服务器可以正确回答

就像4xx系列检查是否可以访问URL一样, 5xx系列检查服务器是否有任何问题回答您的请求。 大部分时间这个家庭的错误是服务器本身的问题,希望他们正在解决这个问题。 如果您需要现在能够访问该页面并获得正确的答案 ,则应确保答案不是来自4xx5xx系列,如果您被redirect,则redirect的页面可以正确回答。 与(2)非常类似,您可以简单地使用以下代码:

 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 

Net::HTTP工作,但如果你能在stdlib之外工作, 法拉第更好。

 Faraday.head(the_url).status == 200 

(200是一个成功的代码,假设这就是你的意思是“存在”。)

你应该阅读这篇文章:

validationRuby on Rails中的URL / URI

西蒙娜的回答对我很有帮助。

这是一个根据URL有效性返回true / false的版本,它处理redirect:

 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