查看源代码 URI (Elixir v1.16.2)
用于处理 URI 的实用程序。
此模块提供用于处理 URI 的函数(例如,解析 URI 或编码查询字符串)。此模块中的函数是根据 RFC 3986 实现的。
摘要
函数
URI 结构。
将 path
附加到给定的 uri
。
将 query
附加到给定的 uri
。
检查 character
是否是 URI 中的保留字符。
检查 character
是否允许在 URI 中不进行转义。
检查 character
是否是 URI 中的未保留字符。
对 URI 进行百分比转义。
将 query
解码为一个 map。
将 string
解码为“x-www-form-urlencoded”。
返回给定 scheme
的默认端口。
为给定的 scheme
注册默认 port
。
对 string
中需要转义的所有字符进行百分比转义。
使用 encoding
将 enumerable
编码为一个查询字符串。
将 string
编码为“x-www-form-urlencoded”。
合并两个 URI。
从 URI 或字符串创建一个新的 URI 结构。
将 URI 解析为其组件,不进行进一步验证。
返回一个流,该流包含表示给定 query
中键值对的两个元素元组。
返回给定 URI 结构 的字符串表示形式。
类型
@opaque authority()
函数
URI 结构。
字段定义为匹配以下 URI 表示形式(字段名称位于方括号中)
[scheme]://[userinfo]@[host]:[port][path]?[query]#[fragment]
请注意,authority
字段已弃用。 parse/1
仍会为了向后兼容而填充它,但您通常应该避免设置或获取它。
将 path
附加到给定的 uri
。
Path 必须以 /
开头,并且不能包含其他 URL 组件,如片段或查询字符串。此函数进一步假设 path 是有效的,并且不包含查询字符串或片段部分。
示例
iex> URI.append_path(URI.parse("http://example.com/foo/?x=1"), "/my-path") |> URI.to_string()
"http://example.com/foo/my-path?x=1"
iex> URI.append_path(URI.parse("http://example.com"), "my-path")
** (ArgumentError) path must start with "/", got: "my-path"
将 query
附加到给定的 uri
。
给定的 query
不会自动进行编码,请使用 encode/2
或 encode_www_form/1
。
示例
iex> URI.append_query(URI.parse("http://example.com/"), "x=1") |> URI.to_string()
"http://example.com/?x=1"
iex> URI.append_query(URI.parse("http://example.com/?x=1"), "y=2") |> URI.to_string()
"http://example.com/?x=1&y=2"
iex> URI.append_query(URI.parse("http://example.com/?x=1"), "x=2") |> URI.to_string()
"http://example.com/?x=1&x=2"
检查 character
是否是 URI 中的保留字符。
如 RFC 3986,第 2.2 节 中所述,以下字符是保留字符::
,/
,?
,#
,[
,]
,@
,!
,$
,&
,'
,(
,)
,*
,+
,,
,;
,=
示例
iex> URI.char_reserved?(?+)
true
检查 character
是否允许在 URI 中不进行转义。
这是 URI.encode/2
使用的默认值,其中 保留字符 和 未保留字符 都保持不转义。
示例
iex> URI.char_unescaped?(?{)
false
检查 character
是否是 URI 中的未保留字符。
如 RFC 3986,第 2.3 节 中所述,以下字符是未保留字符
- 字母数字字符:
A-Z
,a-z
,0-9
~
,_
,-
,.
示例
iex> URI.char_unreserved?(?_)
true
对 URI 进行百分比转义。
示例
iex> URI.decode("https%3A%2F%2Felixir-lang.org")
"https://elixir.erlang.ac.cn"
@spec decode_query(binary(), %{optional(binary()) => binary()}, :rfc3986 | :www_form) :: %{ optional(binary()) => binary() }
将 query
解码为一个 map。
给定一个 key1=value1&key2=value2...
格式的查询字符串,此函数将查询字符串中的每个键值对插入给定 map
中的单个条目中。结果 map 中的键和值将是二进制值。键和值将进行百分比转义。
您可以指定以下 encoding
选项之一
:www_form
- (默认,自 v1.12.0 起)键和值根据decode_www_form/1
进行解码。这是浏览器在查询字符串和表单数据上通常使用的格式。它将 "+" 解码为 " "。:rfc3986
- (自 v1.12.0 起)键和值根据decode/1
进行解码。结果与:www_form
相同,除了根据 RFC 3986 将 "+" 保持原样。
为了向后兼容,编码默认为 :www_form
。
如果您想手动迭代每个值,请使用 query_decoder/1
。
示例
iex> URI.decode_query("foo=1&bar=2")
%{"bar" => "2", "foo" => "1"}
iex> URI.decode_query("percent=oh+yes%21", %{"starting" => "map"})
%{"percent" => "oh yes!", "starting" => "map"}
iex> URI.decode_query("percent=oh+yes%21", %{}, :rfc3986)
%{"percent" => "oh+yes!"}
将 string
解码为“x-www-form-urlencoded”。
请注意,“x-www-form-urlencoded” 未在 RFC 3986 中指定。但是,它是浏览器用于编码查询字符串和表单数据的常用格式。
示例
iex> URI.decode_www_form("%3Call+in%2F")
"<all in/"
@spec default_port(binary()) :: nil | non_neg_integer()
返回给定 scheme
的默认端口。
如果方案对 URI
模块未知,则此函数返回 nil
。任何方案的默认端口可以通过 default_port/2
在全局范围内配置。
示例
iex> URI.default_port("ftp")
21
iex> URI.default_port("ponzi")
nil
@spec default_port(binary(), non_neg_integer()) :: :ok
为给定的 scheme
注册默认 port
。
调用此函数后,port
将由 default_port/1
返回给定方案 scheme
。请注意,此函数会全局更改给定 scheme
的默认端口,这意味着它会影响每个应用程序。
建议您在应用程序的启动回调中调用此函数,如果您要注册新的 URI。
@spec encode(binary(), (byte() -> as_boolean(term()))) :: binary()
对 string
中需要转义的所有字符进行百分比转义。
默认情况下,此函数旨在转义整个 URI,因此它会转义 URI 规范中所有不属于 URI 规范的字符。保留字符(如 :
和 /
)或未保留字符(如字母和数字)不会被转义。
由于 URI 的不同组件需要不同的转义规则,因此此函数还接受一个 predicate
函数作为可选参数。如果传递,此函数将使用 string
中的每个字节作为其参数,如果给定字节应保持原样,则应返回一个真值(除 false
或 nil
之外的任何值),如果字符应进行转义,则返回一个假值(false
或 nil
)。默认为 URI.char_unescaped?/1
。
如果您有兴趣转义保留字符,请参见 encode_www_form/1
。
示例
iex> URI.encode("ftp://s-ite.tld/?value=put it+й")
"ftp://s-ite.tld/?value=put%20it+%D0%B9"
iex> URI.encode("a string", &(&1 != ?i))
"a str%69ng"
@spec encode_query(Enumerable.t(), :rfc3986 | :www_form) :: binary()
使用 encoding
将 enumerable
编码为一个查询字符串。
接受一个可枚举对象,该对象作为两个元素元组列表进行枚举(例如,一个 map 或一个关键字列表),并返回一个 key1=value1&key2=value2...
格式的字符串。
键和值可以是实现了 String.Chars
协议的任何项,但列表除外,列表被明确禁止。
您可以指定以下 encoding
策略之一
:www_form
- (默认,自 v1.12.0 起)键和值根据encode_www_form/1
进行 URL 编码。这是浏览器在查询字符串和表单数据上通常使用的格式。它将 " " 编码为 "+"。:rfc3986
- (自 v1.12.0 起)与:www_form
相同,但根据 RFC 3986 将 " " 编码为 "%20"。如果您在非浏览器环境中进行编码,这是最佳选择,因为将空格编码为 "+" 对 URI 解析器来说可能是模棱两可的。这会无意地导致空格被解释为文字加号。
为了向后兼容,编码默认为 :www_form
。
示例
iex> query = %{"foo" => 1, "bar" => 2}
iex> URI.encode_query(query)
"bar=2&foo=1"
iex> query = %{"key" => "value with spaces"}
iex> URI.encode_query(query)
"key=value+with+spaces"
iex> query = %{"key" => "value with spaces"}
iex> URI.encode_query(query, :rfc3986)
"key=value%20with%20spaces"
iex> URI.encode_query(%{key: [:a, :list]})
** (ArgumentError) encode_query/2 values cannot be lists, got: [:a, :list]
将 string
编码为“x-www-form-urlencoded”。
请注意,“x-www-form-urlencoded” 未在 RFC 3986 中指定。但是,它是浏览器用于编码查询字符串和表单数据的常用格式。
示例
iex> URI.encode_www_form("put: it+й")
"put%3A+it%2B%D0%B9"
合并两个 URI。
此函数根据 RFC 3986,第 5.2 节 合并两个 URI。
示例
iex> URI.merge(URI.parse("http://google.com"), "/query") |> to_string()
"http://google.com/query"
iex> URI.merge("http://example.com", "http://google.com") |> to_string()
"http://google.com"
从 URI 或字符串创建一个新的 URI 结构。
如果给定一个 %URI{}
结构,则返回 {:ok, uri}
。如果给定一个字符串,则会解析并验证它。如果字符串有效,则返回 {:ok, uri}
,否则返回 {:error, part}
,其中包含 URI 的无效部分。要解析 URI 而不进行进一步验证,请参见 parse/1
。
此函数可以解析绝对 URL 和相对 URL。您可以通过检查 scheme
字段是否为 nil
来检查 URI 是否为绝对 URL 或相对 URL。
当给定一个没有端口的 URI 时,会使用 URI.default_port/1
为 URI 的方案返回的值作为 :port
字段。方案也会被规范化为小写。
示例
iex> URI.new("https://elixir.erlang.ac.cn/")
{:ok, %URI{
fragment: nil,
host: "elixir-lang.org",
path: "/",
port: 443,
query: nil,
scheme: "https",
userinfo: nil
}}
iex> URI.new("//elixir.erlang.ac.cn/")
{:ok, %URI{
fragment: nil,
host: "elixir-lang.org",
path: "/",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}}
iex> URI.new("/foo/bar")
{:ok, %URI{
fragment: nil,
host: nil,
path: "/foo/bar",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}}
iex> URI.new("foo/bar")
{:ok, %URI{
fragment: nil,
host: nil,
path: "foo/bar",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}}
iex> URI.new("//[fe80::]/")
{:ok, %URI{
fragment: nil,
host: "fe80::",
path: "/",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}}
iex> URI.new("https:?query")
{:ok, %URI{
fragment: nil,
host: nil,
path: nil,
port: 443,
query: "query",
scheme: "https",
userinfo: nil
}}
iex> URI.new("/invalid_greater_than_in_path/>")
{:error, ">"}
给出已存在的 URI 会简单地将其包装在元组中返回
iex> {:ok, uri} = URI.new("https://elixir.erlang.ac.cn/")
iex> URI.new(uri)
{:ok, %URI{
fragment: nil,
host: "elixir-lang.org",
path: "/",
port: 443,
query: nil,
scheme: "https",
userinfo: nil
}}
类似于 new/1
,但如果给定无效的字符串,则会引发 URI.Error
。
示例
iex> URI.new!("https://elixir.erlang.ac.cn/")
%URI{
fragment: nil,
host: "elixir-lang.org",
path: "/",
port: 443,
query: nil,
scheme: "https",
userinfo: nil
}
iex> URI.new!("/invalid_greater_than_in_path/>")
** (URI.Error) cannot parse due to reason invalid_uri: ">"
给出已存在的 URI 会简单地将其返回
iex> uri = URI.new!("https://elixir.erlang.ac.cn/")
iex> URI.new!(uri)
%URI{
fragment: nil,
host: "elixir-lang.org",
path: "/",
port: 443,
query: nil,
scheme: "https",
userinfo: nil
}
将 URI 解析为其组件,不进行进一步验证。
此函数可以解析绝对 URL 和相对 URL。你可以通过检查 scheme
字段是否为空来检查 URI 是绝对的还是相对的。此外,此函数期望绝对和相对 URI 都是格式良好的,并且不会执行任何验证。请参阅下面的“示例”部分。如果你想在解析后验证 URI 字段,请使用 new/1
。
当给定一个没有端口的 URI 时,会使用 URI.default_port/1
为 URI 的方案返回的值作为 :port
字段。方案也会被规范化为小写。
如果给此函数传递一个 %URI{}
结构体,此函数会将其原样返回。
:authority
字段此函数设置了
:authority
字段,以实现向后兼容性,但已被弃用。
示例
iex> URI.parse("https://elixir.erlang.ac.cn/")
%URI{
authority: "elixir-lang.org",
fragment: nil,
host: "elixir-lang.org",
path: "/",
port: 443,
query: nil,
scheme: "https",
userinfo: nil
}
iex> URI.parse("//elixir.erlang.ac.cn/")
%URI{
authority: "elixir-lang.org",
fragment: nil,
host: "elixir-lang.org",
path: "/",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}
iex> URI.parse("/foo/bar")
%URI{
fragment: nil,
host: nil,
path: "/foo/bar",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}
iex> URI.parse("foo/bar")
%URI{
fragment: nil,
host: nil,
path: "foo/bar",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}
与 URI.new/1
不同,此函数会解析格式不正确的 URI,例如
iex> URI.parse("/invalid_greater_than_in_path/>")
%URI{
fragment: nil,
host: nil,
path: "/invalid_greater_than_in_path/>",
port: nil,
query: nil,
scheme: nil,
userinfo: nil
}
另一个例子是查询字符串中包含方括号的 URI。它会被 parse/1
接受,通常也会被浏览器接受,但会被 new/1
拒绝。
iex> URI.parse("/?foo[bar]=baz")
%URI{
fragment: nil,
host: nil,
path: "/",
port: nil,
query: "foo[bar]=baz",
scheme: nil,
userinfo: nil
}
@spec query_decoder(binary(), :rfc3986 | :www_form) :: Enumerable.t()
返回一个流,该流包含表示给定 query
中键值对的两个元素元组。
每个元组中的键和值都将是二进制,并且将被百分比解码。
您可以指定以下 encoding
选项之一
:www_form
- (默认,自 v1.12.0 起)键和值根据decode_www_form/1
进行解码。这是浏览器在查询字符串和表单数据上通常使用的格式。它将 "+" 解码为 " "。:rfc3986
- (自 v1.12.0 起)键和值根据decode/1
进行解码。结果与:www_form
相同,除了根据 RFC 3986 将 "+" 保持原样。
为了向后兼容,编码默认为 :www_form
。
示例
iex> URI.query_decoder("foo=1&bar=2") |> Enum.to_list()
[{"foo", "1"}, {"bar", "2"}]
iex> URI.query_decoder("food=bread%26butter&drinks=tap%20water+please") |> Enum.to_list()
[{"food", "bread&butter"}, {"drinks", "tap water please"}]
iex> URI.query_decoder("food=bread%26butter&drinks=tap%20water+please", :rfc3986) |> Enum.to_list()
[{"food", "bread&butter"}, {"drinks", "tap water+please"}]
返回给定 URI 结构 的字符串表示形式。
示例
iex> uri = URI.parse("http://google.com")
iex> URI.to_string(uri)
"http://google.com"
iex> uri = URI.parse("foo://bar.baz")
iex> URI.to_string(uri)
"foo://bar.baz"