模組 URI
URI
是提供類別來處理統一資源識別碼 (RFC2396) 的模組。
功能¶ ↑
-
處理 URI 的統一方式。
-
靈活地引入自訂
URI
架構。 -
靈活地擁有備用的
URI::Parser
(或只是不同的模式和正規表示法)。
基本範例¶ ↑
require 'uri' uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413") #=> #<URI::HTTP http://foo.com/posts?id=30&limit=5#time=1305298413> uri.scheme #=> "http" uri.host #=> "foo.com" uri.path #=> "/posts" uri.query #=> "id=30&limit=5" uri.fragment #=> "time=1305298413" uri.to_s #=> "http://foo.com/posts?id=30&limit=5#time=1305298413"
新增自訂 URI¶ ↑
module URI class RSYNC < Generic DEFAULT_PORT = 873 end register_scheme 'RSYNC', RSYNC end #=> URI::RSYNC URI.scheme_list #=> {"FILE"=>URI::File, "FTP"=>URI::FTP, "HTTP"=>URI::HTTP, # "HTTPS"=>URI::HTTPS, "LDAP"=>URI::LDAP, "LDAPS"=>URI::LDAPS, # "MAILTO"=>URI::MailTo, "RSYNC"=>URI::RSYNC} uri = URI("rsync://rsync.foo.com") #=> #<URI::RSYNC rsync://rsync.foo.com>
RFC 參考¶ ↑
檢視 RFC 規格的好地方是 www.ietf.org/rfc.html。
以下是所有相關 RFC 的清單
Class
樹¶ ↑
-
URI::Generic
(在 uri/generic.rb 中)-
URI::File
- (在 uri/file.rb 中) -
URI::FTP
- (在 uri/ftp.rb 中) -
URI::HTTP
- (在 uri/http.rb 中)-
URI::HTTPS
- (在 uri/https.rb 中)
-
-
URI::LDAP
- (在 uri/ldap.rb 中)-
URI::LDAPS
- (在 uri/ldaps.rb 中)
-
-
URI::MailTo
- (在 uri/mailto.rb 中)
-
-
URI::Parser
- (在 uri/common.rb 中) -
URI::REGEXP
- (在 uri/common.rb 中)-
URI::REGEXP::PATTERN - (在 uri/common.rb 中)
-
-
URI::Util - (in uri/common.rb)
-
URI::Error
- (in uri/common.rb)-
URI::InvalidURIError
- (in uri/common.rb) -
URI::InvalidComponentError
- (in uri/common.rb) -
URI::BadURIError
- (in uri/common.rb)
-
版權資訊¶ ↑
- 作者
-
Akira Yamada <[email protected]>
- 文件
-
Akira Yamada <[email protected]> Dmitry V. Sabanin <[email protected]> Vincent Batts <[email protected]>
- 授權
-
版權 © 2001 akira yamada <[email protected]> 您可以在與 Ruby 相同的條款下重新分發和/或修改它。
常數
- DEFAULT_PARSER
- INITIAL_SCHEMES
- Parser
- REGEXP
- RFC3986_PARSER
- TBLENCURICOMP_
公開類別方法
類似於 URI.decode_www_form_component
,但會保留 '+'
。
# File lib/uri/common.rb, line 379 def self.decode_uri_component(str, enc=Encoding::UTF_8) _decode_uri_component(/%\h\h/, str, enc) end
傳回從給定的字串 str
(必須為 ASCII 字串) 衍生的名稱/值對。
此方法可用於解碼 res['Content-Type']
為 'application/x-www-form-urlencoded'
的 Net::HTTPResponse
物件 res
的主體。
傳回的資料是一個 2 元素子陣列的陣列;每個子陣列都是一個名稱/值對 (兩者都是字串)。每個傳回的字串編碼為 enc
,並且已透過 String#scrub
移除無效字元。
一個簡單的範例
URI.decode_www_form('foo=0&bar=1&baz') # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
傳回的字串具有一些轉換,類似於 URI.decode_www_form_component
中執行的轉換
URI.decode_www_form('f%23o=%2F&b-r=%24&b+z=%40') # => [["f#o", "/"], ["b-r", "$"], ["b z", "@"]]
給定的字串可能包含連續的分隔符號
URI.decode_www_form('foo=0&&bar=1&&baz=2') # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
可以指定不同的分隔符號
URI.decode_www_form('foo=0--bar=1--baz', separator: '--') # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
# File lib/uri/common.rb, line 554 def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false) raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only? ary = [] return ary if str.empty? enc = Encoding.find(enc) str.b.each_line(separator) do |string| string.chomp!(separator) key, sep, val = string.partition('=') if isindex if sep.empty? val = key key = +'' end isindex = false end if use__charset_ and key == '_charset_' and e = get_encoding(val) enc = e use__charset_ = false end key.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_) if val val.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_) else val = +'' end ary << [key, val] end ary.each do |k, v| k.force_encoding(enc) k.scrub! v.force_encoding(enc) v.scrub! end ary end
傳回從給定的 URL 編碼字串 str
解碼的字串。
給定的字串首先編碼為 Encoding::ASCII-8BIT (使用 String#b
),然後解碼 (如下所述),最後強制編碼為給定的編碼 enc
。
傳回的字串
-
保留
-
字元
'*'
、'.'
、'-'
和'_'
。 -
範圍
'a'..'z'
、'A'..'Z'
和'0'..'9'
中的字元。
範例
URI.decode_www_form_component('*.-_azAZ09') # => "*.-_azAZ09"
-
-
轉換
-
字元
'+'
至字元' '
。 -
每個「百分比符號」至一個 ASCII 字元。
範例
URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A') # => "Here are some punctuation characters: ,;?:"
-
相關:URI.decode_uri_component
(保留 '+'
)。
# File lib/uri/common.rb, line 368 def self.decode_www_form_component(str, enc=Encoding::UTF_8) _decode_uri_component(/\+|%\h\h/, str, enc) end
類似於 URI.encode_www_form_component
,但將 ' '
(空白)編碼為 '%20'
(而非 '+'
)。
# File lib/uri/common.rb, line 374 def self.encode_uri_component(str, enc=nil) _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc) end
傳回一個 URL 編碼字串,衍生自指定的 Enumerable enum
。
結果適合用於 HTTP 要求的表單資料,其 Content-Type
為 'application/x-www-form-urlencoded'
。
傳回的字串包含 enum
的元素,每個元素轉換為一個或多個 URL 編碼字串,並全部以字元 '&'
連接。
簡單範例
URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]]) # => "foo=0&bar=1&baz=2" URI.encode_www_form({foo: 0, bar: 1, baz: 2}) # => "foo=0&bar=1&baz=2"
傳回的字串使用 URI.encode_www_form_component
方法形成,該方法會轉換特定字元
URI.encode_www_form('f#o': '/', 'b-r': '$', 'b z': '@') # => "f%23o=%2F&b-r=%24&b+z=%40"
當 enum
類似陣列時,每個元素 ele
會轉換為一個欄位
-
如果
ele
是包含兩個或更多元素的陣列,欄位會從其前兩個元素形成(任何其他元素都會被忽略)name = URI.encode_www_form_component(ele[0], enc) value = URI.encode_www_form_component(ele[1], enc) "#{name}=#{value}"
範例
URI.encode_www_form([%w[foo bar], %w[baz bat bah]]) # => "foo=bar&baz=bat" URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']]) # => "foo=0&bar=baz"
-
如果
ele
是包含一個元素的陣列,欄位會從ele[0]
形成URI.encode_www_form_component(ele[0])
範例
URI.encode_www_form([['foo'], [:bar], [0]]) # => "foo&bar&0"
-
否則,欄位會從
ele
形成URI.encode_www_form_component(ele)
範例
URI.encode_www_form(['foo', :bar, 0]) # => "foo&bar&0"
類似陣列的 enum
的元素可能是混合
URI.encode_www_form([['foo', 0], ['bar', 1, 2], ['baz'], :bat]) # => "foo=0&bar=1&baz&bat"
當 enum
類似雜湊時,每個 key
/value
配對會轉換為一個或多個欄位
-
如果
value
是 類似陣列,value
中的每個元素ele
會與key
配對以形成一個欄位name = URI.encode_www_form_component(key, enc) value = URI.encode_www_form_component(ele, enc) "#{name}=#{value}"
範例
URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]}) # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2"
-
否則,
key
和value
會配對以形成一個欄位name = URI.encode_www_form_component(key, enc) value = URI.encode_www_form_component(value, enc) "#{name}=#{value}"
範例
URI.encode_www_form({foo: 0, bar: 1, baz: 2}) # => "foo=0&bar=1&baz=2"
類似雜湊的 enum
的元素可能是混合
URI.encode_www_form({foo: [0, 1], bar: 2}) # => "foo=0&foo=1&bar=2"
# File lib/uri/common.rb, line 501 def self.encode_www_form(enum, enc=nil) enum.map do |k,v| if v.nil? encode_www_form_component(k, enc) elsif v.respond_to?(:to_ary) v.to_ary.map do |w| str = encode_www_form_component(k, enc) unless w.nil? str << '=' str << encode_www_form_component(w, enc) end end.join('&') else str = encode_www_form_component(k, enc) str << '=' str << encode_www_form_component(v, enc) end end.join('&') end
傳回一個 URL 編碼字串,衍生自指定的字串 str
。
傳回的字串
-
保留
-
字元
'*'
、'.'
、'-'
和'_'
。 -
範圍
'a'..'z'
、'A'..'Z'
和'0'..'9'
中的字元。
範例
URI.encode_www_form_component('*.-_azAZ09') # => "*.-_azAZ09"
-
-
轉換
-
字元
' '
至字元'+'
。 -
任何其他字元至「百分比符號」;字元 c 的百分比符號為
'%%%X' % c.ord
。
範例
URI.encode_www_form_component('Here are some punctuation characters: ,;?:') # => "Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A"
-
編碼
-
如果
str
具有編碼 Encoding::ASCII_8BIT,則會忽略參數enc
。 -
否則,會先將
str
轉換為 Encoding::UTF_8(使用適當的字元替換),再轉換為編碼enc
。
在任一種情況下,傳回的字串都強制使用編碼 Encoding::US_ASCII。
相關:URI.encode_uri_component
(將 ' '
編碼為 '%20'
)。
# File lib/uri/common.rb, line 335 def self.encode_www_form_component(str, enc=nil) _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc) end
傳回一個由指定的 scheme
、arguments
和 default
建構的新物件
-
新物件是
URI.scheme_list[scheme.upcase]
的執行個體。 -
使用
scheme
和arguments
呼叫類別初始化函式來初始化物件。請參閱URI::Generic.new
。
範例
values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top'] URI.for('https', *values) # => #<URI::HTTPS https://[email protected]:123/forum/questions/?tag=networking&order=newest#top> URI.for('foo', *values, default: URI::HTTP) # => #<URI::HTTP foo://[email protected]:123/forum/questions/?tag=networking&order=newest#top>
# File lib/uri/common.rb, line 123 def self.for(scheme, *arguments, default: Generic) const_name = scheme.to_s.upcase uri_class = INITIAL_SCHEMES[const_name] uri_class ||= if /\A[A-Z]\w*\z/.match?(const_name) && Schemes.const_defined?(const_name, false) Schemes.const_get(const_name, false) end uri_class ||= default return uri_class.new(scheme, *arguments) end
str
中的每個字串在合併之前會轉換為 RFC3986 URI。
範例
URI.join("http://example.com/","main.rbx") # => #<URI::HTTP http://example.com/main.rbx> URI.join('http://example.com', 'foo') # => #<URI::HTTP http://example.com/foo> URI.join('http://example.com', '/foo', '/bar') # => #<URI::HTTP http://example.com/bar> URI.join('http://example.com', '/foo', 'bar') # => #<URI::HTTP http://example.com/bar> URI.join('http://example.com', '/foo/', 'bar') # => #<URI::HTTP http://example.com/foo/bar>
# File lib/uri/common.rb, line 211 def self.join(*str) RFC3986_PARSER.join(*str) end
允許開啟各種資源,包括 URI。
如果第一個參數回應「open」方法,則會使用其餘參數對其呼叫「open」。
如果第一個參數是從 (protocol)://
開始的字串,則會由 URI.parse
解析。如果解析的物件回應「open」方法,則會使用其餘參數對其呼叫「open」。
否則,會呼叫 Kernel#open
。
OpenURI::OpenRead#open
提供 URI::HTTP#open
、URI::HTTPS#open
和 URI::FTP#open
、Kernel#open
。
我們可以接受 URI 和從 http://、https:// 和 ftp:// 開始的字串。在這些情況下,開啟的檔案物件會由 OpenURI::Meta
延伸。
# File lib/open-uri.rb, line 23 def self.open(name, *rest, &block) if name.respond_to?(:open) name.open(*rest, &block) elsif name.respond_to?(:to_str) && %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ name && (uri = URI.parse(name)).respond_to?(:open) uri.open(*rest, &block) else super end end
傳回由給定字串 uri
建構的新 URI 物件
URI.parse('https://[email protected]:123/forum/questions/?tag=networking&order=newest#top') # => #<URI::HTTPS https://[email protected]:123/forum/questions/?tag=networking&order=newest#top> URI.parse('http://[email protected]:123/forum/questions/?tag=networking&order=newest#top') # => #<URI::HTTP http://[email protected]:123/forum/questions/?tag=networking&order=newest#top>
建議先 ::escape 字串 uri
,如果它可能包含無效的 URI
字元。
# File lib/uri/common.rb, line 184 def self.parse(uri) RFC3986_PARSER.parse(uri) end
註冊給定的 klass
作為在解析具有給定 scheme
的 URI 時要實例化的類別
URI.register_scheme('MS_SEARCH', URI::Generic) # => URI::Generic URI.scheme_list['MS_SEARCH'] # => URI::Generic
請注意,在 scheme
上呼叫 String#upcase
之後,它必須是有效的常數名稱。
# File lib/uri/common.rb, line 79 def self.register_scheme(scheme, klass) Schemes.const_set(scheme.to_s.upcase, klass) end
傳回已定義的 scheme 的雜湊
URI.scheme_list # => {"MAILTO"=>URI::MailTo, "LDAPS"=>URI::LDAPS, "WS"=>URI::WS, "HTTP"=>URI::HTTP, "HTTPS"=>URI::HTTPS, "LDAP"=>URI::LDAP, "FILE"=>URI::File, "FTP"=>URI::FTP}
# File lib/uri/common.rb, line 97 def self.scheme_list Schemes.constants.map { |name| [name.to_s.upcase, Schemes.const_get(name)] }.to_h end
傳回表示由字串 uri
形成的 URI 部分的 9 元素陣列;每個陣列元素都是字串或 nil
names = %w[scheme userinfo host port registry path opaque query fragment] values = URI.split('https://[email protected]:123/forum/questions/?tag=networking&order=newest#top') names.zip(values) # => [["scheme", "https"], ["userinfo", "john.doe"], ["host", "www.example.com"], ["port", "123"], ["registry", nil], ["path", "/forum/questions/"], ["opaque", nil], ["query", "tag=networking&order=newest"], ["fragment", "top"]]
# File lib/uri/common.rb, line 170 def self.split(uri) RFC3986_PARSER.split(uri) end
私人類別方法
# File lib/uri/common.rb, line 397 def self._decode_uri_component(regexp, str, enc) raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/.match?(str) str.b.gsub(regexp, TBLDECWWWCOMP_).force_encoding(enc) end
# File lib/uri/common.rb, line 383 def self._encode_uri_component(regexp, table, str, enc) str = str.to_s.dup if str.encoding != Encoding::ASCII_8BIT if enc && enc != Encoding::ASCII_8BIT str.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace) str.encode!(enc, fallback: ->(x){"&##{x.ord};"}) end str.force_encoding(Encoding::ASCII_8BIT) end str.gsub!(regexp, table) str.force_encoding(Encoding::US_ASCII) end