檢視原始碼 uri_string (stdlib v6.2)
URI 處理函式。
此模組包含用於解析和處理 URI (RFC 3986) 和表單 URL 編碼查詢字串 (HTML 5.2) 的函式。
也支援解析和序列化非 UTF-8 的表單 URL 編碼查詢字串 (HTML 5.0)。
URI 是一個識別符,由符合 RFC 3986 中名為 URI 的語法規則的字元序列組成。
通用 URI 語法由一連串階層式的元件組成,這些元件稱為協定 (scheme)、授權 (authority)、路徑 (path)、查詢 (query) 和片段 (fragment)
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
authority = [ userinfo "@" ] host [ ":" port ]
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
URI 的解讀僅取決於所使用的字元,而不是這些字元在網路協定中的表示方式。
此模組實作的函式涵蓋以下使用情境
- 將 URI 解析為其組成元件並傳回一個 map:
parse/1
- 將 URI 元件的 map 重新組合成 URI 字串:
recompose/1
- 變更 URI 的傳入二進位和百分比編碼:
transcode/2
- 將 URI 轉換為正規化的形式:
normalize/1
、normalize/2
- 從鍵值對列表組合表單 URL 編碼查詢字串:
compose_query/1
、compose_query/2
- 將表單 URL 編碼查詢字串分解為鍵值對列表:
dissect_query/1
- 解碼 URI map 或 URI 特定元件中的百分比編碼三位元組:
percent_decode/1
- 準備和擷取 URI 元件中包含的應用程式特定資料:
quote/1
、quote/2
、unquote/1
在處理 URI 期間存在四種不同的編碼
- 二進位資料中的傳入二進位編碼
- 列表和二進位資料中的傳入百分比編碼
- 二進位資料中的傳出二進位編碼
- 列表和二進位資料中的傳出百分比編碼
具有 uri_string/0
引數的函式接受列表、二進位資料和混合列表(帶有二進位元素的列表)作為輸入類型。除了 transcode/2
之外的所有函式都期望輸入為 Unicode 碼點列表、UTF-8 編碼的二進位資料和 UTF-8 百分比編碼的 URI 部分(「%C3%B6」對應於 Unicode 字元「ö」)。
除非另有指定,否則傳回值類型和編碼與輸入類型和編碼相同。也就是說,二進位輸入會傳回二進位輸出,列表輸入會傳回列表輸出,但混合輸入會傳回列表輸出。
在列表的情況下,只有百分比編碼。然而,在二進位資料中,應考慮二進位編碼和百分比編碼。transcode/2
提供在支援的編碼之間轉換的方法,它接受 uri_string/0
和一個選項列表,用於指定傳入和傳出的編碼。
RFC 3986 沒有強制規定任何特定的字元編碼,它通常由協定或周圍的文字定義。此程式庫採用相同的假設,二進位和百分比編碼被視為一個組態單元來處理,它們不能設定為不同的值。
引號函式旨在由 URI 生產應用程式在元件準備或擷取階段使用,以避免資料與 URI 語法中使用的字元之間發生衝突。引號函式使用百分比編碼,但規則與例如在執行 recompose/1
時的規則不同。使用者有責任僅向引號函式提供應用程式資料,並使用其輸出組合 URI 元件。
例如,引號函式可用於建構一個路徑元件,其中包含一個具有 '/' 字元的片段,該字元不應與在路徑元件中用作一般分隔符的 '/' 衝突。
摘要
類型
表示錯誤類型的錯誤元組。第二個元件的可能值
保留 URI 主要元件的 Map。
Unicode 碼點列表、UTF-8 編碼的二進位資料或兩者的混合,表示符合 RFC 3986 的 URI(百分比編碼形式)。URI 是一個由非常有限的字元集組成的字元序列:基本拉丁字母、數字和一些特殊字元。
函式
這是一個實用函式,旨在在 shell 中使用,用於列印每個主要 URI 元件中允許的字元,以及最重要的字元集中允許的字元。
基於 QueryList
(非百分比編碼鍵值對的列表)組合表單 URL 編碼的 QueryString
。
與 compose_query/1
相同,但帶有一個額外的 Options
參數,該參數控制編碼演算法使用的編碼 (「charset」)。
分解 URL 編碼的 QueryString
並傳回 QueryList
(非百分比編碼鍵值對的列表)。
使用 RFC 3986 定義的基於語法的正規化,將 URI
轉換為正規化的形式。
與 normalize/1
相同,但帶有一個額外的 Options
參數,該參數控制正規化的 URI 是否應作為 uri_map() 傳回。
將符合 RFC 3986 的 uri_string/0
解析為 uri_map/0
,其中保留 URI
的已解析元件。如果解析失敗,則會傳回錯誤元組。
解碼輸入中所有可以同時是 uri_string/0
和 uri_map/0
的百分比編碼三位元組。
將未保留集之外的字元替換為其百分比編碼的等效字元。
與 quote/1
相同,但 Safe
允許使用者提供要保護不被編碼的字元列表。
基於 URIMap
的元件建立符合 RFC 3986 的 URIString
(百分比編碼)。如果 URIMap
無效,則會傳回錯誤元組。
將可能是相對於給定基本 URI 的 RefURI
參考轉換為參考目標的已解析元件,然後可以將這些元件重新組合以形成目標 URI。
與 resolve/2
相同,但帶有一個額外的 Options
參數,該參數控制目標 URI 是否應作為 uri_map() 傳回。有一個支援的選項:return_map
。
轉換符合 RFC 3986 的 URIString
,其中 Options
是一個帶有標記的元組列表,用於指定傳入 (in_encoding
) 和傳出 (out_encoding
) 編碼。
百分比解碼字元。
類型
表示錯誤類型的錯誤元組。第二個元件的可能值
invalid_character
invalid_encoding
invalid_input
invalid_map
invalid_percent_encoding
invalid_scheme
invalid_uri
invalid_utf8
missing_value
第三個元件是一個術語,提供有關錯誤原因的額外資訊。
-type uri_map() :: #{fragment => unicode:chardata(), host => unicode:chardata(), path => unicode:chardata(), port => non_neg_integer() | undefined, query => unicode:chardata(), scheme => unicode:chardata(), userinfo => unicode:chardata()}.
保留 URI 主要元件的 Map。
-type uri_string() :: iodata().
Unicode 碼點列表、UTF-8 編碼的二進位資料或兩者的混合,表示符合 RFC 3986 的 URI(百分比編碼形式)。URI 是一個由非常有限的字元集組成的字元序列:基本拉丁字母、數字和一些特殊字元。
函式
這是一個實用函式,旨在在 shell 中使用,用於列印每個主要 URI 元件中允許的字元,以及最重要的字元集中允許的字元。
請注意,此函式不會取代標準定義的 ABNF 規則,這些字元集直接從上述規則衍生而來。如需更多資訊,請參閱 stdlib 使用者指南中的 統一資源識別碼 章節。
-spec compose_query(QueryList) -> QueryString when QueryList :: [{unicode:chardata(), unicode:chardata() | true}], QueryString :: uri_string() | error().
基於 QueryList
(非百分比編碼鍵值對的列表)組合表單 URL 編碼的 QueryString
。
表單 URL 編碼在 HTML 5.2 規格的 4.10.21.6 節和 HTML 5.0 規格的 4.10.22.6 節中針對非 UTF-8 編碼定義。
另請參閱相反的操作 dissect_query/1
。
範例
1> uri_string:compose_query([{"foo bar","1"},{"city","örebro"}]).
"foo+bar=1&city=%C3%B6rebro"
2> uri_string:compose_query([{<<"foo bar">>,<<"1">>},
2> {<<"city">>,<<"örebro"/utf8>>}]).
<<"foo+bar=1&city=%C3%B6rebro">>
-spec compose_query(QueryList, Options) -> QueryString when QueryList :: [{unicode:chardata(), unicode:chardata() | true}], Options :: [{encoding, atom()}], QueryString :: uri_string() | error().
與 compose_query/1
相同,但帶有一個額外的 Options
參數,該參數控制編碼演算法使用的編碼 (「charset」)。
有兩種支援的編碼:utf8
(或 unicode
) 和 latin1
。
項目名稱和值中無法使用選取的字元編碼表示的每個字元,都將被一個字串取代,該字串由一個 U+0026 連字號字元 (&)、一個「#」 (U+0023) 字元、一個或多個 ASCII 數字(表示字元的 Unicode 碼點的十進位數字),最後是一個「;」 (U+003B) 字元組成。
超出範圍 0x2A、0x2D、0x2E、0x30 至 0x39、0x41 至 0x5A、0x5F、0x61 至 0x7A 的位元組會進行百分比編碼 (以 U+0025 百分比符號字元 (%) 作為開頭,後接代表該位元組十六進位值的 ASCII 大寫十六進位數字)。
另請參閱相反的操作 dissect_query/1
。
範例
1> uri_string:compose_query([{"foo bar","1"},{"city","örebro"}],
1> [{encoding, latin1}]).
"foo+bar=1&city=%F6rebro"
2> uri_string:compose_query([{<<"foo bar">>,<<"1">>},
2> {<<"city">>,<<"東京"/utf8>>}], [{encoding, latin1}]).
<<"foo+bar=1&city=%26%2326481%3B%26%2320140%3B">>
-spec dissect_query(QueryString) -> QueryList when QueryString :: uri_string(), QueryList :: [{unicode:chardata(), unicode:chardata() | true}] | error().
分解 URL 編碼的 QueryString
並傳回 QueryList
(非百分比編碼鍵值對的列表)。
表單 URL 編碼在 HTML 5.2 規格的 4.10.21.6 節和 HTML 5.0 規格的 4.10.22.6 節中針對非 UTF-8 編碼定義。
另請參閱相反的操作 compose_query/1
。
範例
1> uri_string:dissect_query("foo+bar=1&city=%C3%B6rebro").
[{"foo bar","1"},{"city","örebro"}]
2> uri_string:dissect_query(<<"foo+bar=1&city=%26%2326481%3B%26%2320140%3B">>).
[{<<"foo bar">>,<<"1">>},
{<<"city">>,<<230,157,177,228,186,172>>}]
-spec normalize(URI) -> NormalizedURI when URI :: uri_string() | uri_map(), NormalizedURI :: uri_string() | error().
使用 RFC 3986 定義的基於語法的正規化,將 URI
轉換為正規化的形式。
此函式實作了大小寫正規化、百分比編碼正規化、路徑區段正規化以及 HTTP(S) 的基於方案的正規化,並基本支援 FTP、SSH、SFTP 和 TFTP。
範例
1> uri_string:normalize("/a/b/c/./../../g").
"/a/g"
2> uri_string:normalize(<<"mid/content=5/../6">>).
<<"mid/6">>
3> uri_string:normalize("https://127.0.0.1:80").
"https://127.0.0.1/"
4> uri_string:normalize(#{scheme => "http",port => 80,path => "/a/b/c/./../../g",
4> host => "localhost-örebro"}).
"https://127.0.0.1-%C3%B6rebro/a/g"
-spec normalize(URI, Options) -> NormalizedURI when URI :: uri_string() | uri_map(), Options :: [return_map], NormalizedURI :: uri_string() | uri_map() | error().
與 normalize/1
相同,但帶有一個額外的 Options
參數,該參數控制正規化的 URI 是否應作為 uri_map() 傳回。
有一個支援的選項:return_map
。
範例
1> uri_string:normalize("/a/b/c/./../../g", [return_map]).
#{path => "/a/g"}
2> uri_string:normalize(<<"mid/content=5/../6">>, [return_map]).
#{path => <<"mid/6">>}
3> uri_string:normalize("https://127.0.0.1:80", [return_map]).
#{scheme => "http",path => "/",host => "localhost"}
4> uri_string:normalize(#{scheme => "http",port => 80,path => "/a/b/c/./../../g",
4> host => "localhost-örebro"}, [return_map]).
#{scheme => "http",path => "/a/g",host => "localhost-örebro"}
-spec parse(URIString) -> URIMap when URIString :: uri_string(), URIMap :: uri_map() | error().
將符合 RFC 3986 的 uri_string/0
解析為 uri_map/0
,其中保留 URI
的已解析元件。如果解析失敗,則會傳回錯誤元組。
另請參閱相反的操作 recompose/1
。
範例
1> uri_string:parse("foo://user@example.com:8042/over/there?name=ferret#nose").
#{fragment => "nose",host => "example.com",
path => "/over/there",port => 8042,query => "name=ferret",
scheme => foo,userinfo => "user"}
2> uri_string:parse(<<"foo://user@example.com:8042/over/there?name=ferret">>).
#{host => <<"example.com">>,path => <<"/over/there">>,
port => 8042,query => <<"name=ferret">>,scheme => <<"foo">>,
userinfo => <<"user">>}
-spec percent_decode(URI) -> Result when URI :: uri_string() | uri_map(), Result :: uri_string() | uri_map() | {error, {invalid, {atom(), {term(), term()}}}} | error().
解碼輸入中所有可以同時是 uri_string/0
和 uri_map/0
的百分比編碼三位元組。
請注意,此函式執行原始解碼,應在已剖析的 URI 元件上使用。直接在標準 URI 上套用此函式可能會有效地變更它。
如果輸入編碼不是 UTF-8,則會傳回錯誤元組。
範例
1> uri_string:percent_decode(#{host => "localhost-%C3%B6rebro",path => [],
1> scheme => "http"}).
#{host => "localhost-örebro",path => [],scheme => "http"}
2> uri_string:percent_decode(<<"%C3%B6rebro">>).
<<"örebro"/utf8>>
警告
直接在 URI 上使用
uri_string:percent_decode/1
是不安全的。此範例顯示,在每次連續套用該函式後,產生的 URI 都會變更。這些 URI 都沒有參考同一個資源。3> uri_string:percent_decode(<<"http://local%252Fhost/path">>). <<"http://local%2Fhost/path">> 4> uri_string:percent_decode(<<"http://local%2Fhost/path">>). <<"http://local/host/path">>
-spec quote(Data) -> QuotedData when Data :: unicode:chardata(), QuotedData :: unicode:chardata().
將未保留集之外的字元替換為其百分比編碼的等效字元。
在 RFC 3986 中定義的未保留字元不會被引號括住。
範例
1> uri_string:quote("SomeId/04").
"SomeId%2F04"
2> uri_string:quote(<<"SomeId/04">>).
<<"SomeId%2F04">>
警告
函式不了解任何 URI 元件的上下文,不應在整個 URI 上使用。如果對相同資料套用多次,可能會產生非預期的結果。
-spec quote(Data, Safe) -> QuotedData when Data :: unicode:chardata(), Safe :: string(), QuotedData :: unicode:chardata().
與 quote/1
相同,但 Safe
允許使用者提供要保護不被編碼的字元列表。
範例
1> uri_string:quote("SomeId/04", "/").
"SomeId/04"
2> uri_string:quote(<<"SomeId/04">>, "/").
<<"SomeId/04">>
警告
函式不了解任何 URI 元件的上下文,不應在整個 URI 上使用。如果對相同資料套用多次,可能會產生非預期的結果。
-spec recompose(URIMap) -> URIString when URIMap :: uri_map(), URIString :: uri_string() | error().
基於 URIMap
的元件建立符合 RFC 3986 的 URIString
(百分比編碼)。如果 URIMap
無效,則會傳回錯誤元組。
另請參閱相反的操作 parse/1
。
範例
1> URIMap = #{fragment => "nose", host => "example.com", path => "/over/there",
1> port => 8042, query => "name=ferret", scheme => "foo", userinfo => "user"}.
#{fragment => "nose",host => "example.com",
path => "/over/there",port => 8042,query => "name=ferret",
scheme => "foo",userinfo => "user"}
2> uri_string:recompose(URIMap).
"foo://example.com:8042/over/there?name=ferret#nose"
-spec resolve(RefURI, BaseURI) -> TargetURI when RefURI :: uri_string() | uri_map(), BaseURI :: uri_string() | uri_map(), TargetURI :: uri_string() | error().
將可能是相對於給定基本 URI 的 RefURI
參考轉換為參考目標的已解析元件,然後可以將這些元件重新組合以形成目標 URI。
範例
1> uri_string:resolve("/abs/ol/ute", "https://127.0.0.1/a/b/c?q").
"https://127.0.0.1/abs/ol/ute"
2> uri_string:resolve("../relative", "https://127.0.0.1/a/b/c?q").
"https://127.0.0.1/a/relative"
3> uri_string:resolve("https://127.0.0.1/full", "https://127.0.0.1/a/b/c?q").
"https://127.0.0.1/full"
4> uri_string:resolve(#{path => "path", query => "xyz"}, "https://127.0.0.1/a/b/c?q").
"https://127.0.0.1/a/b/path?xyz"
-spec resolve(RefURI, BaseURI, Options) -> TargetURI when RefURI :: uri_string() | uri_map(), BaseURI :: uri_string() | uri_map(), Options :: [return_map], TargetURI :: uri_string() | uri_map() | error().
與 resolve/2
相同,但帶有一個額外的 Options
參數,該參數控制目標 URI 是否應作為 uri_map() 傳回。有一個支援的選項:return_map
。
範例
1> uri_string:resolve("/abs/ol/ute", "https://127.0.0.1/a/b/c?q", [return_map]).
#{host => "localhost",path => "/abs/ol/ute",scheme => "http"}
2> uri_string:resolve(#{path => "/abs/ol/ute"}, #{scheme => "http",
2> host => "localhost", path => "/a/b/c?q"}, [return_map]).
#{host => "localhost",path => "/abs/ol/ute",scheme => "http"}
-spec transcode(URIString, Options) -> Result when URIString :: uri_string(), Options :: [{in_encoding, unicode:encoding()} | {out_encoding, unicode:encoding()}], Result :: uri_string() | error().
轉換符合 RFC 3986 的 URIString
,其中 Options
是一個帶有標記的元組列表,用於指定傳入 (in_encoding
) 和傳出 (out_encoding
) 編碼。
in_encoding
和 out_encoding
指定輸入和輸出資料的二進位編碼和百分比編碼。不支援混合編碼,其中二進位編碼與百分比編碼不同。如果引數無效,則會傳回錯誤元組。
範例
1> uri_string:transcode(<<"foo%00%00%00%F6bar"/utf32>>,
1> [{in_encoding, utf32},{out_encoding, utf8}]).
<<"foo%C3%B6bar"/utf8>>
2> uri_string:transcode("foo%F6bar", [{in_encoding, latin1},
2> {out_encoding, utf8}]).
"foo%C3%B6bar"
-spec unquote(QuotedData) -> Data when QuotedData :: unicode:chardata(), Data :: unicode:chardata().
百分比解碼字元。
範例
1> uri_string:unquote("SomeId%2F04").
"SomeId/04"
2> uri_string:unquote(<<"SomeId%2F04">>).
<<"SomeId/04">>
警告
函式不了解任何 URI 元件的上下文,不應在整個 URI 上使用。如果對相同資料套用多次,可能會產生非預期的結果。