我想验证 uri,例如:
http://vk.com
http://semantic-ui.com/collections/menu.html
https://translate.yandex.ru/?text=poll&lang=en-ru
而不是
www.vk.com
abdeeej
http://vk
但还没有找到它的任何本机代码实现包。
我该怎么做?
根据规范,所有这些在技术上都是有效的 URL,因此
URI.parse/1
为所有内容返回一个 %URI{}
结构,但如果您想拒绝没有 scheme
且 host
中没有点的域,您可以这样做:
valid? = fn url ->
uri = URI.parse(url)
uri.scheme != nil && uri.host =~ "."
end
测试:
urls = [
"http://vk.com",
"http://semantic-ui.com/collections/menu.html",
"https://translate.yandex.ru/?text=poll&lang=en-ru",
"www.vk.com",
"abdeeej",
"http://vk"
]
urls |> Enum.map(valid?) |> IO.inspect
输出:
[true, true, true, false, false, false]
这个解决方案更完整:
def validate_url(changeset, field, opts \\ []) do
validate_change(changeset, field, fn _, value ->
case URI.parse(value) do
val(%URI{scheme: nil}) ->
"is missing a scheme (e.g. https)"
%URI{host: nil} ->
"is missing a host"
%URI{host: host} ->
case :inet.gethostbyname(Kernel.to_charlist(host)) do
{:ok, _} -> nil
{:error, _} -> "invalid host"
end
end
|> case do
error when is_binary(error) -> [{field, Keyword.get(opts, :message, error)}]
_ -> []
end
end)
end
摘自https://gist.github.com/atomkirk/74b39b5b09c7d0f21763dd55b877f998
自从 elixir
1.13.0
以来,验证 url 的方法是使用 URI.new/1
。它将获取 url 字符串,对其进行解析和验证,如果有效则返回 %{:ok, url}
,否则返回 %{:error, invalid_part_of_the_url}
表示无效 url。然后,可以使用结果 {:ok, struct}
的模式匹配在更细粒度的级别进行验证。有关更多信息,请在 IEx 中运行 h URI.new
。
注意:URI.new/1 在编码不良或未编码的 url 上失败,例如未编码且包含空格的 url,并返回错误。
# Without encoding, notice the space in the url
iex(1)> URI.new("https://testdomain/Teams/Odense Boldklub.png")
{:error, ":"}
# After encoding URL
iex(9)> URI.encode("https://testdomain/Teams/Odense Boldklub.png") |> URI.new
{:ok,
%URI{
scheme: "https",
userinfo: nil,
host: "testdomain",
port: 443,
path: "/Teams/Odense%20Boldklub.png",
query: nil,
fragment: nil
}}