檢視原始碼 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 期間存在四種不同的編碼

  • 二進位資料中的傳入二進位編碼
  • 列表和二進位資料中的傳入百分比編碼
  • 二進位資料中的傳出二進位編碼
  • 列表和二進位資料中的傳出百分比編碼

具有 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 3986uri_string/0 解析為 uri_map/0,其中保留 URI 的已解析元件。如果解析失敗,則會傳回錯誤元組。

解碼輸入中所有可以同時是 uri_string/0uri_map/0 的百分比編碼三位元組。

將未保留集之外的字元替換為其百分比編碼的等效字元。

quote/1 相同,但 Safe 允許使用者提供要保護不被編碼的字元列表。

基於 URIMap 的元件建立符合 RFC 3986URIString(百分比編碼)。如果 URIMap 無效,則會傳回錯誤元組。

將可能是相對於給定基本 URI 的 RefURI 參考轉換為參考目標的已解析元件,然後可以將這些元件重新組合以形成目標 URI。

resolve/2 相同,但帶有一個額外的 Options 參數,該參數控制目標 URI 是否應作為 uri_map() 傳回。有一個支援的選項:return_map

轉換符合 RFC 3986URIString,其中 Options 是一個帶有標記的元組列表,用於指定傳入 (in_encoding) 和傳出 (out_encoding) 編碼。

百分比解碼字元。

類型

連結到此類型

error()

檢視原始碼 (自 OTP 21.0 起)
-type error() :: {error, atom(), term()}.

表示錯誤類型的錯誤元組。第二個元件的可能值

  • invalid_character
  • invalid_encoding
  • invalid_input
  • invalid_map
  • invalid_percent_encoding
  • invalid_scheme
  • invalid_uri
  • invalid_utf8
  • missing_value

第三個元件是一個術語,提供有關錯誤原因的額外資訊。

連結到此類型

uri_map()

檢視原始碼 (自 OTP 21.0 起)
-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。

連結到此類型

uri_string()

檢視原始碼 (自 OTP 21.0 起)
-type uri_string() :: iodata().

Unicode 碼點列表、UTF-8 編碼的二進位資料或兩者的混合,表示符合 RFC 3986 的 URI(百分比編碼形式)。URI 是一個由非常有限的字元集組成的字元序列:基本拉丁字母、數字和一些特殊字元。

函式

連結到此函式

allowed_characters()

檢視原始碼 (自 OTP 23.2 起)
-spec allowed_characters() -> [{atom(), list()}].

這是一個實用函式,旨在在 shell 中使用,用於列印每個主要 URI 元件中允許的字元,以及最重要的字元集中允許的字元。

請注意,此函式不會取代標準定義的 ABNF 規則,這些字元集直接從上述規則衍生而來。如需更多資訊,請參閱 stdlib 使用者指南中的 統一資源識別碼 章節。

連結到此函式

compose_query(QueryList)

檢視原始碼 (自 OTP 21.0 起)
-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">>
連結到此函式

compose_query(QueryList, Options)

檢視原始碼 (自 OTP 21.0 起)
-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">>
連結到此函式

dissect_query(QueryString)

檢視原始碼 (自 OTP 21.0 起)
-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>>}]
連結到此函式

normalize(URI)

檢視原始碼 (自 OTP 21.0 起)
-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"
連結到此函式

normalize(URI, Options)

檢視原始碼 (自 OTP 21.0 起)
-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"}
連結到此函式

parse(URIString)

檢視原始碼 (自 OTP 21.0 起)
-spec parse(URIString) -> URIMap when URIString :: uri_string(), URIMap :: uri_map() | error().

將符合 RFC 3986uri_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">>}
連結到此函式

percent_decode(URI)

檢視原始碼 (自 OTP 23.2 起)
-spec percent_decode(URI) -> Result
                        when
                            URI :: uri_string() | uri_map(),
                            Result ::
                                uri_string() |
                                uri_map() |
                                {error, {invalid, {atom(), {term(), term()}}}} |
                                error().

解碼輸入中所有可以同時是 uri_string/0uri_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">>
連結到此函式

quote(Data)

檢視原始碼 (自 OTP 25.0 起)
-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 上使用。如果對相同資料套用多次,可能會產生非預期的結果。

連結到此函式

quote(Data, Safe)

檢視原始碼 (自 OTP 25.0 起)
-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 上使用。如果對相同資料套用多次,可能會產生非預期的結果。

連結到此函式

recompose(URIMap)

檢視原始碼 (自 OTP 21.0 起)
-spec recompose(URIMap) -> URIString when URIMap :: uri_map(), URIString :: uri_string() | error().

基於 URIMap 的元件建立符合 RFC 3986URIString(百分比編碼)。如果 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"
連結到此函式

resolve(RefURI, BaseURI)

檢視原始碼 (自 OTP 22.3 起)
-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"
連結到此函式

resolve(RefURI, BaseURI, Options)

檢視原始碼 (自 OTP 22.3 起)
-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"}
連結到此函式

transcode(URIString, Options)

檢視原始碼 (自 OTP 21.0 起)
-spec transcode(URIString, Options) -> Result
                   when
                       URIString :: uri_string(),
                       Options ::
                           [{in_encoding, unicode:encoding()} | {out_encoding, unicode:encoding()}],
                       Result :: uri_string() | error().

轉換符合 RFC 3986URIString,其中 Options 是一個帶有標記的元組列表,用於指定傳入 (in_encoding) 和傳出 (out_encoding) 編碼。

in_encodingout_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"
連結到此函式

unquote(QuotedData)

檢視原始碼 (自 OTP 25.0 起)
-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 上使用。如果對相同資料套用多次,可能會產生非預期的結果。