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

在Ruby中打开包含下划线的URL有解决方法吗?,ruby,open-uri,Ruby,Open Uri,我正在使用openuri来打开url resp = open("http://sub_domain.domain.com") 如果它包含下划线,则会出现错误: URI::InvalidURIError: the scheme http does not accept registry part: sub_domain.domain.com (or bad hostname?) URI::InvalidURIError:方案http不接受注册表部分:sub_domain.domain.com(或

我正在使用openuri来打开url

resp = open("http://sub_domain.domain.com")
如果它包含下划线,则会出现错误:

URI::InvalidURIError: the scheme http does not accept registry part: sub_domain.domain.com (or bad hostname?) URI::InvalidURIError:方案http不接受注册表部分:sub_domain.domain.com(或坏主机名?)
我理解这是因为根据RFC,URL只能包含字母和数字。有什么解决办法吗?

这样的域名不能包含下划线。这是DNS标准的一部分。你是想用破折号(
-
)吗

即使openuri没有抛出错误,这样的命令也毫无意义。为什么?因为它无法解析这样的域名。充其量只能得到一个
未知主机
错误。您无法使用
\uu
注册域名,即使运行自己的专用DNS服务器,使用
\u
也违反规范。你可以改变规则并允许它(通过修改DNS服务器软件),但是你的操作系统的DNS解析器将不支持它,你的路由器的DNS软件也不支持它


解决方案:不要尝试在DNS名称中使用
。它在任何地方都不起作用,而且违反了规范这看起来像是URI中的一个bug,而URI open、HttpParty和许多其他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")

我建议使用路缘宝石:它只包装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类,因为它们与规范太过严格,正如你所知,web是一个狂野的西部:)Curl/curb像champ一样处理我抛出的每个url。

我的rails应用程序中的这个初始值设定项似乎使URI.parse至少能够工作:

#config/initializers/uri_underline.rb
类URI::泛型
def使用注册表检查初始化注册表(方案,
用户信息、主机、端口、注册表、,
路径,不透明,
查询
碎片,
parser=默认的\u解析器,
arg_check=false)
如果%w(http https).include?(scheme)&&host.nil?&&注册表=~/_/
在没有注册表检查的情况下初始化注册表(scheme、userinfo、注册表、端口、nil、path、不透明、查询、片段、解析器、arg\u检查)
其他的
在没有注册表检查的情况下初始化注册表(方案、用户信息、主机、端口、注册表、路径、不透明、查询、片段、解析器、参数检查)
结束
结束
别名\u方法\u链:初始化,:注册表\u检查
结束

URI
对url的外观有一个老式的概念

要绕过这个问题:

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安装可寻址的

这里是另一个丑陋的黑客,不需要gem:

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

我在尝试使用gem update/gem install等时也遇到了同样的错误。因此,我改用了IP地址,现在一切正常。

这里有一个补丁,可以解决各种情况下(rest客户端、开放uri等)的问题,而无需使用外部gem或重写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
资料来源:


Ruby core有一个悬而未决的问题:

对于任何遇到这个问题的人:

Ruby的
URI.parse过去是基于RFC2396(1998年8月发布),请参见


但是从Ruby2.2URI开始,如果您使用的是现代版本,那么现在就不需要猴子补丁了。

不,我的意思就是下划线。正如我所提到的,我知道这是标准所不允许的,但也有类似的URL(例如在livejournal.com上),我必须处理它们。@Arty啊,我还没有意识到像livejournal这样的大玩家会允许这样的RFC破坏。嗯,我不知道:呃,下划线不是保留字符。它是无保留的。不仅仅是livejournal可以做到这一点,Windows允许在机器名中使用下划线,这样你就可以得到一个有下划线的坏主机名。诚如Tin Man所说,由于下划线是无保留字符,因此在通用URI的主机名部分允许使用下划线,但这与Earlz所说的并不矛盾,即您不能(成功地)在DNS中使用此类主机名。URI中允许它的事实并不意味着它将实际解析,这可能是合理的,因为注册的域和可解析的主机不是URI的唯一可能用途。子域允许有下划线。这是一个丑陋的黑客,但它的工作。问题是,我们的一个合作伙伴强迫我们使用这个域名,我们甚至必须将它添加到所有服务器上的主机文件中,因为它无法解决。。。非常好<代码>可寻址::URI
比ruby core的URI更接近RFC如果您使用Rails,这是最好的解决方案。谢谢@Cluesques这一款很好用。但它给出了一个警告,因为常量DEFAULT_解析器已经存在。为了防止这种情况,我使用了:模块URI original\u verbose,$verbose=$verbose,nil DEFAULT\u PARSER=PARSER.new(:HOSTNAME=>“(?:(?:[a-zA-Z\\d](?:[-\\u a-zA-Z\\d]*[a-zA-Z\\d])\\)*(?:[a-zA-Z](?:[-\\u a-zA-zA-Z\\d]*[a-zA-Z\\d])\.)$VERBOSE=original_VERBOSE end`这也解决了我在使用URI.extract时遇到的问题,它在子域中带有下划线的链接上断开。