如何使用Ruby检查URL是否存在?
例如,对于URL
https://google.com
结果应该是 truthy ,但对于网址
https://no.such.domain
或
https://stackoverflow.com/no/such/path
结果应为 falsey
答案 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)
对于迟到的回复对不起,但我认为这可以提供更好的答案。
有三种方法可以看待这个问题:
虽然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
但是,大多数时候我们都不想知道网址是否存在,但是我们是否可以访问。幸运的是找到了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
就像4xx
家庭检查您是否可以访问该网址一样,5xx
家庭会检查服务器是否在回答您的请求时遇到任何问题。大多数时候这个家庭的错误是服务器本身的问题,希望他们正在努力解决它。如果您需要能够访问该网页并立即获得正确答案,则应确保答案不是来自4xx
或5xx
家庭,如果您是重定向,重定向页面正确回答。与(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