Есть ли обходной путь для открытия URL-адресов, содержащих подчеркивания в Ruby? - PullRequest
31 голосов
/ 06 марта 2011

Я использую open-uri для открытия 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?)

Я понимаю, что это потому, что в соответствии с RFC URL-адреса могут содержать только буквы и цифры.Есть ли обходной путь?

Ответы [ 8 ]

19 голосов
/ 06 марта 2011

Это похоже на ошибку в 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")
17 голосов
/ 14 июня 2013

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

14 голосов
/ 11 февраля 2013

Этот инициализатор в моем приложении 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 голосов
/ 09 декабря 2016

Вот патч, который решает проблему для самых разных ситуаций (rest-client, open-uri и т. Д.) Без использования внешних гемов или переопределяющих частей 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

3 голосов
/ 06 марта 2011

Подчеркивание не может содержаться в таком доменном имени.Это является частью стандарта DNS.Вы хотели использовать тире (-)?

Даже если open-uri не выдавал ошибку, такая команда была бы бессмысленной.Зачем?Потому что нет способа разрешить такое доменное имя.В лучшем случае вы получите ошибку unknown host.У вас нет возможности зарегистрировать доменное имя с _, и даже если вы используете свой собственный DNS-сервер, использование спецификации _ противоречит спецификации.Вы можете изменить правила и разрешить их (путем изменения программного обеспечения DNS-сервера), но тогда DNS-распознаватель вашей операционной системы не будет поддерживать его, равно как и программное обеспечение DNS вашего маршрутизатора.

Решение: не пытайтесь использовать _ в DNS-имени.Это нигде не будет работать, и это против спецификации

2 голосов
/ 23 октября 2013

У меня была такая же ошибка при попытке использовать gem update / gem install и т. Д., Поэтому я использовал вместо этого IP-адрес, и теперь все нормально.

2 голосов
/ 22 сентября 2013

Вот еще один уродливый хак, драгоценность не нужна:

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
0 голосов
/ 18 мая 2012

Я рекомендую использовать драгоценный камень Curb: 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 обрабатывает каждый URL, который я кидаю, как чемпион.

...