我该如何使用 Ruby 检查 URL 是否存在?
例如,对于以下 URL:
https://google.com
结果应该是真值,但对于URL来说
https://no.such.domain
或者https://stackoverflow.com/no/such/path
结果应为falsey
我该如何使用 Ruby 检查 URL 是否存在?
例如,对于以下 URL:
https://google.com
结果应该是真值,但对于URL来说
https://no.such.domain
或者https://stackoverflow.com/no/such/path
结果应为falsey
使用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)
http://www.http:/
这个URL并给出了200 OK..但是这是错误的...问题在哪里?有任何想法吗?注意:本地环境下这个工作正常。 - Jay_Pandyaaddress = [url.path, url.query].compact.split('').flatten.join('?')
或者在 Rails 中使用 [url.path.presence || '/', url.query.presence].compact.join('?')
,然后执行 req.request_head(address)
。 - Nic Nilovrequire "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
然而,大多数情况下我们并不关心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
就像 4xx
系列检查您是否可以访问URL一样,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
行更改为
path = url.path if url.path.present?和
req.request_head(path || '/')`来解决。 - Yo Ludkerescue Errno::ENOENT false #如果找不到服务器,则返回false rescue URI::InvalidURIError false #如果URI无效,则返回false rescue SocketError false #如果无法打开TCP连接,则返回false rescue Errno::ECONNREFUSED false #如果无法打开TCP连接,则返回false rescue Net::OpenTimeout false #如果执行超时,则返回false rescue OpenSSL::SSL::SSLError false
- CamilleNet::HTTP
可以使用,但如果你可以不依赖于标准库的话,Faraday 更好。
Faraday.head(the_url).status == 200
(假设"存在"是指200状态码表示成功。)
.success?
。这将返回任何状态码从200
到299
的true
,并对所有其他状态码返回false
。https://github.com/lostisland/faraday/search?q=SuccessfulStatuses - Joshua PinterSimone的回答对我很有帮助。
这里有一个版本,根据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