35

我正在使用 open-uri 打开 URL。

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

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

URI::InvalidURIError:http 方案不接受注册表部分:sub_domain.domain.com(或错误的主机名?)

我知道这是因为根据 RFC URL 只能包含字母和数字。有什么解决方法吗?

4

9 回答 9

20

这看起来像是 URI 中的一个错误,并且 uri-open、HTTParty 和许多其他 gem 都使用了 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")
于 2011-03-06T08:49:50.253 回答
18

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

最近我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

于 2013-06-14T12:07:24.823 回答
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
于 2013-02-11T15:51:58.833 回答
6

这是一个补丁,它在不使用外部 gem 或覆盖 URI.parse 的部分的情况下解决了各种情况(rest-client、open-uri 等)的问题:

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

于 2016-12-08T21:08:07.297 回答
3

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

即使 open-uri 没有抛出错误,这样的命令也毫无意义。为什么?因为没有办法解析这样的域名。充其量你会得到一个unknown host错误。注册域名是没有办法的_,即使运行自己的私有 DNS 服务器,使用_. 您可以改变规则并允许它(通过修改 DNS 服务器软件),但是您的操作系统的 DNS 解析器将不支持它,您的路由器的 DNS 软件也不支持。

解决方案:不要尝试_在 DNS 名称中使用 a。它在任何地方都不起作用,而且违反了规范

于 2011-03-06T05:17:12.237 回答
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
于 2013-09-21T22:18:33.547 回答
2

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

于 2013-10-23T13:11:39.327 回答
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 / Curl 处理我像冠军一样扔给它的每个 url。

于 2012-05-18T14:34:17.363 回答
0

对于任何偶然发现这一点的人:

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

但是从 ruby​​ 2.2 开始,URI升级为 RFC 3986,所以如果你使用的是现代版本,现在不需要猴子补丁。

于 2020-04-21T20:20:58.830 回答