查看源代码 URI (Elixir v1.16.2)

用于处理 URI 的实用程序。

此模块提供用于处理 URI 的函数(例如,解析 URI 或编码查询字符串)。此模块中的函数是根据 RFC 3986 实现的。

摘要

类型

authority() 已弃用
t()

函数

URI 结构。

path 附加到给定的 uri

query 附加到给定的 uri

检查 character 是否是 URI 中的保留字符。

检查 character 是否允许在 URI 中不进行转义。

检查 character 是否是 URI 中的未保留字符。

对 URI 进行百分比转义。

string 解码为“x-www-form-urlencoded”。

返回给定 scheme 的默认端口。

为给定的 scheme 注册默认 port

string 中需要转义的所有字符进行百分比转义。

使用 encodingenumerable 编码为一个查询字符串。

string 编码为“x-www-form-urlencoded”。

合并两个 URI。

从 URI 或字符串创建一个新的 URI 结构。

类似于 new/1,但如果给定无效的字符串,则会引发 URI.Error

将 URI 解析为其组件,不进行进一步验证。

返回一个流,该流包含表示给定 query 中键值对的两个元素元组。

返回给定 URI 结构 的字符串表示形式。

类型

此不透明类型已弃用。authority 字段已弃用。
@opaque authority()
@type t() :: %URI{
  authority: authority(),
  fragment: nil | binary(),
  host: nil | binary(),
  path: nil | binary(),
  port: nil | :inet.port_number(),
  query: nil | binary(),
  scheme: nil | binary(),
  userinfo: nil | binary()
}

函数

URI 结构。

字段定义为匹配以下 URI 表示形式(字段名称位于方括号中)

[scheme]://[userinfo]@[host]:[port][path]?[query]#[fragment]

请注意,authority 字段已弃用。 parse/1 仍会为了向后兼容而填充它,但您通常应该避免设置或获取它。

链接到此函数

append_path(uri, path)

查看源代码 (自 1.15.0 起)
@spec append_path(t(), String.t()) :: t()

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"
链接到此函数

append_query(uri, query)

查看源代码 (自 1.14.0 起)
@spec append_query(t(), binary()) :: t()

query 附加到给定的 uri

给定的 query 不会自动进行编码,请使用 encode/2encode_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"
链接到此函数

char_reserved?(character)

查看源代码
@spec char_reserved?(byte()) :: boolean()

检查 character 是否是 URI 中的保留字符。

RFC 3986,第 2.2 节 中所述,以下字符是保留字符::/?#[]@!$&'()*+,;=

示例

iex> URI.char_reserved?(?+)
true
链接到此函数

char_unescaped?(character)

查看源代码
@spec char_unescaped?(byte()) :: boolean()

检查 character 是否允许在 URI 中不进行转义。

这是 URI.encode/2 使用的默认值,其中 保留字符未保留字符 都保持不转义。

示例

iex> URI.char_unescaped?(?{)
false
链接到此函数

char_unreserved?(character)

查看源代码
@spec char_unreserved?(byte()) :: boolean()

检查 character 是否是 URI 中的未保留字符。

RFC 3986,第 2.3 节 中所述,以下字符是未保留字符

  • 字母数字字符:A-Za-z0-9
  • ~, _, -, .

示例

iex> URI.char_unreserved?(?_)
true
@spec decode(binary()) :: binary()

对 URI 进行百分比转义。

示例

iex> URI.decode("https%3A%2F%2Felixir-lang.org")
"https://elixir.erlang.ac.cn"
链接到此函数

decode_query(query, map \\ %{}, encoding \\ :www_form)

查看源代码
@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!"}
链接到此函数

decode_www_form(string)

查看源代码
@spec decode_www_form(binary()) :: binary()

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
链接到此函数

default_port(scheme, port)

查看源代码
@spec default_port(binary(), non_neg_integer()) :: :ok

为给定的 scheme 注册默认 port

调用此函数后,port 将由 default_port/1 返回给定方案 scheme。请注意,此函数会全局更改给定 scheme 的默认端口,这意味着它会影响每个应用程序。

建议您在应用程序的启动回调中调用此函数,如果您要注册新的 URI。

链接到此函数

encode(string, predicate \\ &char_unescaped?/1)

查看源代码
@spec encode(binary(), (byte() -> as_boolean(term()))) :: binary()

string 中需要转义的所有字符进行百分比转义。

默认情况下,此函数旨在转义整个 URI,因此它会转义 URI 规范中所有不属于 URI 规范的字符。保留字符(如 :/)或未保留字符(如字母和数字)不会被转义。

由于 URI 的不同组件需要不同的转义规则,因此此函数还接受一个 predicate 函数作为可选参数。如果传递,此函数将使用 string 中的每个字节作为其参数,如果给定字节应保持原样,则应返回一个真值(除 falsenil 之外的任何值),如果字符应进行转义,则返回一个假值(falsenil)。默认为 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"
链接到此函数

encode_query(enumerable, encoding \\ :www_form)

查看源代码
@spec encode_query(Enumerable.t(), :rfc3986 | :www_form) :: binary()

使用 encodingenumerable 编码为一个查询字符串。

接受一个可枚举对象,该对象作为两个元素元组列表进行枚举(例如,一个 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]
链接到此函数

encode_www_form(string)

查看源代码
@spec encode_www_form(binary()) :: binary()

string 编码为“x-www-form-urlencoded”。

请注意,“x-www-form-urlencoded” 未在 RFC 3986 中指定。但是,它是浏览器用于编码查询字符串和表单数据的常用格式。

示例

iex> URI.encode_www_form("put: it+й")
"put%3A+it%2B%D0%B9"
@spec merge(t() | binary(), t() | binary()) :: t()

合并两个 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"
链接到此函数

new(uri)

查看源代码 (自 1.13.0 起)
@spec new(t() | String.t()) :: {:ok, t()} | {:error, String.t()}

从 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!(uri)

查看源代码 (自 1.13.0 起)
@spec new!(t() | String.t()) :: t()

类似于 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
}
@spec parse(t() | binary()) :: t()

将 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
}
链接到此函数

query_decoder(query, encoding \\ :www_form)

查看源代码
@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"}]
@spec to_string(t()) :: binary()

返回给定 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"