检查Ruby中是否存在URL

Shr*_*war 53 ruby

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

例如,对于URL

https://google.com
Run Code Online (Sandbox Code Playgroud)

结果应该是真实的,但对于URL

https://no.such.domain
Run Code Online (Sandbox Code Playgroud)

要么

https://stackoverflow.com/no/such/path
Run Code Online (Sandbox Code Playgroud)

结果应该是假的

Sim*_*tti 66

使用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)
Run Code Online (Sandbox Code Playgroud)

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

do_something_with_it(url) if res.code == "200"
Run Code Online (Sandbox Code Playgroud)

注意:要检查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)
Run Code Online (Sandbox Code Playgroud)

  • 重定向怎么样?302 http代码 (4认同)

fot*_*nus 53

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

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

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

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
Run Code Online (Sandbox Code Playgroud)

2.检查您是否正在请求URL correclty

但是,大多数时候我们不想看看URL是否存在,但是我们是否可以访问它.幸运的是,查看HTTP状态代码系列,即4xx系列客户端错误的状态(因此,您身边的错误,这意味着您没有正确请求页面,没有权限或任何权限).检查是否可以访问此页面时,这是一个很好的错误.来自维基:

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
Run Code Online (Sandbox Code Playgroud)

3.检查您是否可以正确请求它,服务器可以正确回答

就像4xx家人检查您是否可以访问URL一样,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
Run Code Online (Sandbox Code Playgroud)

  • 我不得不添加一些救援来管理其他情况:`救援Errno :: ENOENT false #false如果找不到服务器救援URI :: InvalidURIError false #false如果URI无效rescue SocketError false #false如果无法打开TCP连接救援Errno :: ECONNREFUSED false #false如果无法打开TCP连接救援Net :: OpenTimeout false #false如果执行过期救援OpenSSL :: SSL :: SSLError false (5认同)
  • 如果您使用 https-url 执行此操作,您可能会收到“Net::HTTPBadResponse: wrong status line”错误。这是因为您必须告诉 Net:HTTP 使用 ssl。为了使它也适用于 https,在调用 `request_head` 之前放置一行 `req.use_ssl = (url.scheme == 'https')` (2认同)

Tur*_*adg 26

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

Faraday.head(the_url).status == 200
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么你认为它更好? (7认同)
  • 您也可以使用[RestClient库](https://github.com/rest-client/rest-client).`require'rest_client'; RestClient.head(url).code!= 404` (2认同)