Open-uriを使用してURLを開いています。
resp = open("http://sub_domain.domain.com")
アンダースコアが含まれていると、エラーが発生します。
URI :: InvalidURIError:スキームhttpはレジストリ部分を受け入れません:sub_domain.domain.com(または不正なホスト名?)
これは、RFCによると、URLには文字と数字のみを含めることができるためです。回避策はありますか?
これは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")
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
を忘れずに
この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
このようなドメイン名にアンダースコアを含めることはできません。これはDNS標準の一部です。ダッシュ(-
)を使用するつもりでしたか?
Open-uriがエラーをスローしなかったとしても、そのようなコマンドは無意味です。どうして?そのようなドメイン名を解決できる方法がないためです。せいぜいunknown Host
エラーが発生します。 _
を使用してドメイン名を登録する方法はなく、独自のプライベートDNSサーバーを実行している場合でも、_
を使用することは仕様に反しています。ルールを曲げて許可することもできますが(DNSサーバーソフトウェアを変更することにより)、オペレーティングシステムのDNSリゾルバーはこれをサポートせず、ルーターのDNSソフトウェアもサポートしません。
解決策:DNS名に_
を使用しないでください。それはどこでも機能せず、仕様に違反しています
以下は、外部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
Gem update/gem installなどを使用しようとしたときに同じエラーが発生したため、代わりにIPアドレスを使用しましたが、現在は問題ありません。
ここに別の醜いハックがあります、宝石は必要ありません:
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
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クラスは、Webが野生の西であることがわかるように仕様が厳しすぎるため、避けます。).