检查Ruby中是否存在URL

时间:2011-05-06 07:15:33

标签: ruby

如何使用Ruby检查URL是否存在?

例如,对于URL

https://google.com

结果应该是 truthy ,但对于网址

https://no.such.domain

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

结果应为 falsey

4 个答案:

答案 0 :(得分:65)

使用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的网址,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 :(得分:52)

对于迟到的回复对不起,但我认为这可以提供更好的答案。

有三种方法可以看待这个问题:

  1. 严格检查网址是否存在
  2. 检查您是否正在请求URL correclty
  3. 检查您是否可以正确请求并且服务器可以正确回答
  4. 1。严格检查URL是否存在

    虽然200表示服务器应答该URL(因此,URL存在),但回答其他状态代码并不意味着该URL不存在。例如,回答302 - redirected表示URL存在并重定向到另一个URL。在浏览时,302多次与最终用户的200行为相同。如果存在URL,则可以返回的其他状态代码是500 - internal server error。毕竟,如果URL不存在,那么应用程序服务器如何处理您的请求而只返回404 - not found

    因此,当URL不存在时,实际上只有两种情况:当服务器不存在或服务器存在但无法找到给定的URL路径时,不存在。 因此,检查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

    但是,大多数时候我们都不想知道网址是否存在,但是我们是否可以访问。幸运的是找到了HTTP status codes个系列,即4xx系列,它指出客户端错误(因此,您身边的错误,这意味着您没有正确请求页面,没有权限)或者无论如何)。检查是否可以访问此页面时,这是一个很好的错误。来自wiki:

      

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

    以下代码确保网址存在且您可以访问

    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家庭检查您是否可以访问该网址一样,5xx家庭会检查服务器是否在回答您的请求时遇到任何问题。大多数时候这个家庭的错误是服务器本身的问题,希望他们正在努力解决它。如果您需要能够访问该网页并立即获得正确答案,则应确保答案不是来自4xx5xx家庭,如果您是重定向,重定向页面正确回答。与(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
    

答案 2 :(得分:26)

Net::HTTP有效,但如果您可以在stdlib外工作,Faraday会更好。

Faraday.head(the_url).status == 200

(200是成功代码,假设你的意思是"存在"。)

答案 3 :(得分:3)

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

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

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