查看源代码 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 主要组件的映射。

Unicode 码位列表、UTF-8 编码的二进制数据或两者的混合,表示符合 RFC 3986 的 URI(百分比编码形式)。URI 是来自非常有限的字符集的字符序列:基本拉丁字母的字母、数字和一些特殊字符。

函数

这是一个实用函数,旨在在 shell 中使用,用于打印每个主要 URI 组件以及最重要的字符集中允许的字符。

基于 QueryList(非百分比编码的键值对列表)组合一个表单 URL 编码的 QueryString

compose_query/1 相同,但带有一个额外的 Options 参数,用于控制编码算法使用的编码(“字符集”)。

分解一个 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 主要组件的映射。

链接到此类型

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 参数,用于控制编码算法使用的编码(“字符集”)。

支持两种编码:utf8 (或 unicode) 和 latin1

条目名称和值中,任何无法使用所选字符编码表示的字符,都会被替换为一个字符串,该字符串由一个 U+0026 AMPERSAND 字符 (&),一个 "#" (U+0023) 字符,一个或多个表示该字符 Unicode 代码点(十进制)的 ASCII 数字,以及最后的一个 ";" (U+003B) 字符组成。

超出 0x2A、0x2D、0x2E、0x30 到 0x39、0x41 到 0x5A、0x5F、0x61 到 0x7A 范围的字节会进行百分比编码(使用 U+0025 PERCENT SIGN 字符 (%),后跟表示该字节十六进制值的大写 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://[email protected]: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://[email protected]: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 上使用。如果对同一数据应用多次,可能会产生意外的结果。