是否有解决方法在Ruby中打开包含下划线的URL?

时间:2011-03-06 05:13:42

标签: ruby open-uri

我正在使用open-uri打开网址。

resp = open("http://sub_domain.domain.com")

如果它包含下划线,我会收到错误:

URI::InvalidURIError: the scheme http does not accept registry part: sub_domain.domain.com (or bad hostname?)

据我所知,这是因为根据RFC网址只能包含字母和数字。有没有解决方法?

9 个答案:

答案 0 :(得分:19)

这看起来像是URI中的错误,而uri-open,HTTParty和许多其他宝石都使用URI.parse。

这是一种解决方法:

require 'net/http'
require 'open-uri'

def hopen(url)
  begin
    open(url)
  rescue URI::InvalidURIError
    host = url.match(".+\:\/\/([^\/]+)")[1]
    path = url.partition(host)[2] || "/"
    Net::HTTP.get host, path
  end
end

resp = hopen("http://dear_raed.blogspot.com/2009_01_01_archive.html")

答案 1 :(得分:17)

URI对网址的外观有一个老式的想法。

Lately I'm using addressable解决这个问题:

require 'open-uri'
require 'addressable/uri'

class URI::Parser
  def split url
    a = Addressable::URI::parse url
    [a.scheme, a.userinfo, a.host, a.port, nil, a.path, nil, a.query, a.fragment]
  end
end

resp = open("http://sub_domain.domain.com") # Yay!

不要忘记gem install addressable

答案 2 :(得分:14)

我的rails应用程序中的这个初始化程序似乎至少使URI.parse工作:

# config/initializers/uri_underscore.rb
class URI::Generic
  def initialize_with_registry_check(scheme,
                 userinfo, host, port, registry,
                 path, opaque,
                 query,
                 fragment,
                 parser = DEFAULT_PARSER,
                 arg_check = false)
    if %w(http https).include?(scheme) && host.nil? && registry =~ /_/
      initialize_without_registry_check(scheme, userinfo, registry, port, nil, path, opaque, query, fragment, parser, arg_check)
    else
      initialize_without_registry_check(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser, arg_check)
    end
  end
  alias_method_chain :initialize, :registry_check
end

答案 3 :(得分:3)

下划线不能包含在这样的域名中。这是DNS标准的一部分。您的意思是使用短划线(-)吗?

即使open-uri没有抛出错误,这样的命令也毫无意义。为什么?因为没有办法解决这样的域名。最多会出现unknown host错误。您无法在其中注册包含_的域名,甚至无法运行您自己的私有DNS服务器,因此使用_符合规范。您可以弯曲规则并允许它(通过修改DNS服务器软件),但是您的操作系统的DNS解析器将不支持它,您的路由器的DNS软件也不支持。

解决方案:请勿尝试在DNS名称中使用_。它不会在任何地方工作,它违反了规范

答案 4 :(得分:3)

这是一个补丁,可以解决各种情况(rest-client,open-uri等)的问题,而无需使用外部gem或覆盖URI.parse的部分:

module URI
  DEFAULT_PARSER = Parser.new(:HOSTNAME => "(?:(?:[a-zA-Z\\d](?:[-\\_a-zA-Z\\d]*[a-zA-Z\\d])?)\\.)*(?:[a-zA-Z](?:[-\\_a-zA-Z\\d]*[a-zA-Z\\d])?)\\.?")
end

来源:lib/uri/rfc2396_parser.rb#L86

Ruby-core有一个未解决的问题:https://bugs.ruby-lang.org/issues/8241

答案 5 :(得分:2)

这是另一个丑陋的黑客,不需要宝石:

def parse(url = nil)
    begin
        URI.parse(url)
    rescue URI::InvalidURIError
        host = url.match(".+\:\/\/([^\/]+)")[1]
        uri = URI.parse(url.sub(host, 'dummy-host'))
        uri.instance_variable_set('@host', host)
        uri
    end
end

答案 6 :(得分:2)

我在尝试使用gem update / gem install等时遇到了同样的错误,所以我现在使用的是IP地址而且它很好。

答案 7 :(得分:0)

我建议使用Curb gem:https://github.com/taf2/curb,它只包含libcurl。这是一个简单的示例,它将自动跟踪重定向并打印响应代码和响应正文:

rsp = Curl::Easy.http_get(url){|curl| curl.follow_location = true; curl.max_redirects=10;}
puts rsp.response_code
puts rsp.body_str

我通常会避免使用ruby URI类,因为它们太严格了,因为你知道网络是疯狂的西部:) Curl / curb处理我扔给它的每个网址就像一个冠军。

答案 8 :(得分:0)

对于绊倒这个的人:

Ruby的URI.parse曾经基于RFC2396(于1998年8月发布),请参见https://bugs.ruby-lang.org/issues/8241

但是从ruby 2.2 URI开始是upgraded into RFC 3986,因此,如果您使用的是现代版本,则现在不需要猴子补丁。