With block in Plug server 抛出 MatchError 而不是使用 else 块
With block in Plug server throws MatchError instead of using else block
以前,我会在 Elixir Plug 服务器中使用 with
块来解析来自请求的参数,如果失败,我会 return 一个理智的响应。但是,这似乎不再有效(Elixir 1.11)。谁能指出发生了什么事?
这是一个极简主义的 Plug
服务器,它会显示问题
defmodule MatchTest.Router do
use Plug.Router
plug(:match)
plug(:dispatch)
get "/" do
other_with =
with {:ok, _} <- Map.fetch(%{}, "test") do
:ok
else
:error -> :error
end
with conn <- Plug.Conn.fetch_query_params(conn),
{:ok, a} = Map.fetch(conn.query_params, "a") do
Plug.Conn.send_resp(conn, 200, "a = #{a}; other_with = #{other_with}")
else
:error -> Plug.Conn.send_resp(conn, 400, "Incorrect Parameters")
end
end
match _ do
Plug.Conn.send_resp(conn, 404, "Not Found")
end
end
defmodule MatchTest do
use Application
def start(_type, _args) do
Supervisor.start_link(
[{Plug.Cowboy, scheme: :http, plug: MatchTest.Router, options: [port: 4000]}],
strategy: :one_for_one,
name: RateLimitedServer.Supervisor
)
end
end
正如预期的那样,当我在 GET 请求中包含 a
参数时一切正常:
ddrexler@Drexbook-Pro:temp|$ http -v get localhost:4000/ a=="test"
GET /?a=test HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:4000
User-Agent: HTTPie/2.3.0
HTTP/1.1 200 OK
cache-control: max-age=0, private, must-revalidate
content-length: 28
date: Mon, 15 Feb 2021 22:40:14 GMT
server: Cowboy
a = test; other_with = error
特别是,第一个 with
子句按预期工作,当我们尝试从空映射 Map.fetch()
时,它跳转到 else
子句(您可以看到这是因为字符串“other_with = error”).
但是,当我尝试排除参数时,我得到了 500:
ddrexler@Drexbook-Pro:~|$ http -v get localhost:4000/
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:4000
User-Agent: HTTPie/2.3.0
HTTP/1.1 500 Internal Server Error
content-length: 0
并且服务器收到未捕获的 MatchError:
ddrexler@Drexbook-Pro:match_test|$ mix run --no-halt
Compiling 1 file (.ex)
warning: "else" clauses will never match because all patterns in "with" will always match
lib/match_test.ex:15
14:40:16.341 [error] #PID<0.350.0> running MatchTest.Router (connection #PID<0.349.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /
** (exit) an exception was raised:
** (MatchError) no match of right hand side value: :error
(match_test 0.1.0) lib/match_test.ex:16: anonymous fn/2 in MatchTest.Router.do_match/4
(match_test 0.1.0) lib/plug/router.ex:284: MatchTest.Router.dispatch/2
(match_test 0.1.0) lib/match_test.ex:1: MatchTest.Router.plug_builder_call/2
(plug_cowboy 2.4.1) lib/plug/cowboy/handler.ex:12: Plug.Cowboy.Handler.init/2
(cowboy 2.8.0) /Users/ddrexler/src/elixir/match_test/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
(cowboy 2.8.0) /Users/ddrexler/src/elixir/match_test/deps/cowboy/src/cowboy_stream_h.erl:300: :cowboy_stream_h.execute/3
(cowboy 2.8.0) /Users/ddrexler/src/elixir/match_test/deps/cowboy/src/cowboy_stream_h.erl:291: :cowboy_stream_h.request_process/3
(stdlib 3.13.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
另请注意警告 "else" clauses will never match because all patterns in "with" will always match
- 显然不正确!有一种情况是它们不匹配,因为我得到了 MatchError。 else
块包含一个 :error
选项,应该捕获此结果!
你可能已经从@sbacarob 的评论中算出来了。
您的错误即将到来,因为当没有 a
参数时:{:ok, a} = Map.fetch(conn.query_params, "a")
被评估为 {:ok, a} = :error
并引发 MatchError
.
要避免 MatchError
,您需要使用特殊的 with
-特定运算符 <-
。您可以将其视为“软匹配”运算符(其中 =
是“硬匹配”)。软匹配让匹配失败(在 with
中)并下降到 else/end,而硬匹配将引发 MatchError
.
以前,我会在 Elixir Plug 服务器中使用 with
块来解析来自请求的参数,如果失败,我会 return 一个理智的响应。但是,这似乎不再有效(Elixir 1.11)。谁能指出发生了什么事?
这是一个极简主义的 Plug
服务器,它会显示问题
defmodule MatchTest.Router do
use Plug.Router
plug(:match)
plug(:dispatch)
get "/" do
other_with =
with {:ok, _} <- Map.fetch(%{}, "test") do
:ok
else
:error -> :error
end
with conn <- Plug.Conn.fetch_query_params(conn),
{:ok, a} = Map.fetch(conn.query_params, "a") do
Plug.Conn.send_resp(conn, 200, "a = #{a}; other_with = #{other_with}")
else
:error -> Plug.Conn.send_resp(conn, 400, "Incorrect Parameters")
end
end
match _ do
Plug.Conn.send_resp(conn, 404, "Not Found")
end
end
defmodule MatchTest do
use Application
def start(_type, _args) do
Supervisor.start_link(
[{Plug.Cowboy, scheme: :http, plug: MatchTest.Router, options: [port: 4000]}],
strategy: :one_for_one,
name: RateLimitedServer.Supervisor
)
end
end
正如预期的那样,当我在 GET 请求中包含 a
参数时一切正常:
ddrexler@Drexbook-Pro:temp|$ http -v get localhost:4000/ a=="test"
GET /?a=test HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:4000
User-Agent: HTTPie/2.3.0
HTTP/1.1 200 OK
cache-control: max-age=0, private, must-revalidate
content-length: 28
date: Mon, 15 Feb 2021 22:40:14 GMT
server: Cowboy
a = test; other_with = error
特别是,第一个 with
子句按预期工作,当我们尝试从空映射 Map.fetch()
时,它跳转到 else
子句(您可以看到这是因为字符串“other_with = error”).
但是,当我尝试排除参数时,我得到了 500:
ddrexler@Drexbook-Pro:~|$ http -v get localhost:4000/
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:4000
User-Agent: HTTPie/2.3.0
HTTP/1.1 500 Internal Server Error
content-length: 0
并且服务器收到未捕获的 MatchError:
ddrexler@Drexbook-Pro:match_test|$ mix run --no-halt
Compiling 1 file (.ex)
warning: "else" clauses will never match because all patterns in "with" will always match
lib/match_test.ex:15
14:40:16.341 [error] #PID<0.350.0> running MatchTest.Router (connection #PID<0.349.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /
** (exit) an exception was raised:
** (MatchError) no match of right hand side value: :error
(match_test 0.1.0) lib/match_test.ex:16: anonymous fn/2 in MatchTest.Router.do_match/4
(match_test 0.1.0) lib/plug/router.ex:284: MatchTest.Router.dispatch/2
(match_test 0.1.0) lib/match_test.ex:1: MatchTest.Router.plug_builder_call/2
(plug_cowboy 2.4.1) lib/plug/cowboy/handler.ex:12: Plug.Cowboy.Handler.init/2
(cowboy 2.8.0) /Users/ddrexler/src/elixir/match_test/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
(cowboy 2.8.0) /Users/ddrexler/src/elixir/match_test/deps/cowboy/src/cowboy_stream_h.erl:300: :cowboy_stream_h.execute/3
(cowboy 2.8.0) /Users/ddrexler/src/elixir/match_test/deps/cowboy/src/cowboy_stream_h.erl:291: :cowboy_stream_h.request_process/3
(stdlib 3.13.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
另请注意警告 "else" clauses will never match because all patterns in "with" will always match
- 显然不正确!有一种情况是它们不匹配,因为我得到了 MatchError。 else
块包含一个 :error
选项,应该捕获此结果!
你可能已经从@sbacarob 的评论中算出来了。
您的错误即将到来,因为当没有 a
参数时:{:ok, a} = Map.fetch(conn.query_params, "a")
被评估为 {:ok, a} = :error
并引发 MatchError
.
要避免 MatchError
,您需要使用特殊的 with
-特定运算符 <-
。您可以将其视为“软匹配”运算符(其中 =
是“硬匹配”)。软匹配让匹配失败(在 with
中)并下降到 else/end,而硬匹配将引发 MatchError
.