尝试在 Phoenix 中发送 HTTP 状态代码时出错
Error when trying to send HTTP status code in Phoenix
我是 Phoenix/Elixir 初学者,正在尝试编写一个 API 以允许用户在我的应用程序中注册。
API 端点按预期工作,除非我尝试设置响应的 HTTP 状态代码。当我包含 A、B 和 C 行(在下面的代码中指示)时,我得到一个 FunctionClauseError
和消息 no function clause matching in :cowboy_req.status/1
.
完整的报错信息如下:
[error] #PID<0.344.0> running App.Endpoint terminated
Server: localhost:4000 (http)
Request: POST /api/user/
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in :cowboy_req.status/1
(cowboy) src/cowboy_req.erl:1272: :cowboy_req.status(451)
(cowboy) src/cowboy_req.erl:1202: :cowboy_req.response/6
(cowboy) src/cowboy_req.erl:933: :cowboy_req.reply_no_compress/8
(cowboy) src/cowboy_req.erl:888: :cowboy_req.reply/4
(plug) lib/plug/adapters/cowboy/conn.ex:34: Plug.Adapters.Cowboy.Conn.send_resp/4
(plug) lib/plug/conn.ex:356: Plug.Conn.send_resp/1
(app) web/controllers/user_controller.ex:1: App.UserController.action/2
(app) web/controllers/user_controller.ex:1: App.UserController.phoenix_controller_app/2
(app) lib/app/endpoint.ex:1: App.Endpoint.instrument/4
(app) lib/phoenix/router.ex:261: App.Router.dispatch/2
(app) web/router.ex:1: App.Router.do_call/2
(app) lib/app/endpoint.ex:1: App.Endpoint.phoenix_app/1
(app) lib/plug/debugger.ex:122: App.Endpoint."call (overridable 3)"/2
(app) lib/app/endpoint.ex:1: App.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
我的代码如下:
defmodule App.UserController do
use App.Web, :controller
import Ecto.Changeset
alias App.User
alias App.Session
def create(conn, params) do
changeset = User.changeset(%User{}, params)
case Repo.insert(changeset) do
{:ok, _user} ->
email = get_field(changeset, :email)
password = get_field(changeset, :password)
# Log on user upon sign up
session_changeset = Session.changeset(%Session{
email: email,
password: password
})
result = Repo.insert(session_changeset)
case result do
{:ok, session} ->
conn
|> put_resp_cookie("SID", session.session_id)
|> put_status(201) # line A
|> render("signup.json", data: %{
changeset: changeset
})
{:error, changeset} ->
conn
|> put_status(251) # line B
|> render("signup.json", data: %{
changeset: changeset
})
end
{:error, changeset} ->
conn
|> put_status(451) # line C
|> render("signup.json", data: %{
changeset: changeset
})
end
end
end
为什么会这样,我哪里出错了?
编辑 自 2016 年 10 月 22 日起,现在可以在 Plug master 上使用。这是文档的相关部分以供参考:
Custom status codes
Plug allows status codes to be overridden or added in order to allow new codes not directly specified by Plug or
its adapters. Adding or overriding a status code is done through the
Mix configuration of the :plug
application. For example, to
override the existing 404 reason phrase for the 404 status code
("Not Found" by default) and add a new 451 status code, the following
config can be specified:
config :plug, :statuses, %{
404 => "Actually This Was Found",
451 => "Unavailable For Legal Reasons"
}
As this configuration is Plug specific, Plug will need to be recompiled for the changes to take place: this will not happen
automatically as dependencies are not automatically recompiled when
their configuration changes.
To recompile Plug:
MIX_ENV=prod mix deps.compile plug
The atoms that can be used in place of the status code in many functions are inflected from the
reason phrase of the status code. With the above configuration, the
following will all work:
put_status(conn, :not_found) # 404
put_status(conn, :actually_this_was_found) # 404
put_status(conn, :unavailable_for_legal_reasons) # 451
Even though 404 has been overridden, the :not_found
atom can still be
used to set the status to 404 as well as the new atom
:actually_this_was_found
inflected from the reason phrase
"Actually This Was Found".
Cowboy 手动指定 HTTP 响应代码并匹配指定的整数。
https://github.com/ninenines/cowboy/blob/1.0.x/src/cowboy_req.erl#L1318
允许二进制文件,但是这样做:
conn
|> put_status("451 Unavailable For Legal Reasons")
不会工作,因为插件只允许整数或已知原子。
这应该被认为是一个错误。您可以尝试在我链接的文件中获取 Cowboy 的拉取请求。
如果无法将 PR 合并到 Cowboy 中,也可以通过转换状态在 Cowboy 适配器的 Plug 中执行(这是一个幼稚的解决方案):
status = if (status == 451) do
"451 Unavailable For Legal Reasons"
else
status
end
在此文件中https://github.com/elixir-lang/plug/blob/master/lib/plug/adapters/cowboy/conn.ex#L33
另见 https://github.com/ninenines/cowboy/issues/965 and https://github.com/elixir-lang/plug/issues/451
我是 Phoenix/Elixir 初学者,正在尝试编写一个 API 以允许用户在我的应用程序中注册。
API 端点按预期工作,除非我尝试设置响应的 HTTP 状态代码。当我包含 A、B 和 C 行(在下面的代码中指示)时,我得到一个 FunctionClauseError
和消息 no function clause matching in :cowboy_req.status/1
.
完整的报错信息如下:
[error] #PID<0.344.0> running App.Endpoint terminated
Server: localhost:4000 (http)
Request: POST /api/user/
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in :cowboy_req.status/1
(cowboy) src/cowboy_req.erl:1272: :cowboy_req.status(451)
(cowboy) src/cowboy_req.erl:1202: :cowboy_req.response/6
(cowboy) src/cowboy_req.erl:933: :cowboy_req.reply_no_compress/8
(cowboy) src/cowboy_req.erl:888: :cowboy_req.reply/4
(plug) lib/plug/adapters/cowboy/conn.ex:34: Plug.Adapters.Cowboy.Conn.send_resp/4
(plug) lib/plug/conn.ex:356: Plug.Conn.send_resp/1
(app) web/controllers/user_controller.ex:1: App.UserController.action/2
(app) web/controllers/user_controller.ex:1: App.UserController.phoenix_controller_app/2
(app) lib/app/endpoint.ex:1: App.Endpoint.instrument/4
(app) lib/phoenix/router.ex:261: App.Router.dispatch/2
(app) web/router.ex:1: App.Router.do_call/2
(app) lib/app/endpoint.ex:1: App.Endpoint.phoenix_app/1
(app) lib/plug/debugger.ex:122: App.Endpoint."call (overridable 3)"/2
(app) lib/app/endpoint.ex:1: App.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
我的代码如下:
defmodule App.UserController do
use App.Web, :controller
import Ecto.Changeset
alias App.User
alias App.Session
def create(conn, params) do
changeset = User.changeset(%User{}, params)
case Repo.insert(changeset) do
{:ok, _user} ->
email = get_field(changeset, :email)
password = get_field(changeset, :password)
# Log on user upon sign up
session_changeset = Session.changeset(%Session{
email: email,
password: password
})
result = Repo.insert(session_changeset)
case result do
{:ok, session} ->
conn
|> put_resp_cookie("SID", session.session_id)
|> put_status(201) # line A
|> render("signup.json", data: %{
changeset: changeset
})
{:error, changeset} ->
conn
|> put_status(251) # line B
|> render("signup.json", data: %{
changeset: changeset
})
end
{:error, changeset} ->
conn
|> put_status(451) # line C
|> render("signup.json", data: %{
changeset: changeset
})
end
end
end
为什么会这样,我哪里出错了?
编辑 自 2016 年 10 月 22 日起,现在可以在 Plug master 上使用。这是文档的相关部分以供参考:
Custom status codes
Plug allows status codes to be overridden or added in order to allow new codes not directly specified by Plug or its adapters. Adding or overriding a status code is done through the Mix configuration of the
:plug
application. For example, to override the existing 404 reason phrase for the 404 status code
("Not Found" by default) and add a new 451 status code, the following config can be specified:config :plug, :statuses, %{ 404 => "Actually This Was Found", 451 => "Unavailable For Legal Reasons" }
As this configuration is Plug specific, Plug will need to be recompiled for the changes to take place: this will not happen automatically as dependencies are not automatically recompiled when their configuration changes. To recompile Plug:
MIX_ENV=prod mix deps.compile plug
The atoms that can be used in place of the status code in many functions are inflected from the reason phrase of the status code. With the above configuration, the following will all work:
put_status(conn, :not_found) # 404 put_status(conn, :actually_this_was_found) # 404 put_status(conn, :unavailable_for_legal_reasons) # 451
Even though 404 has been overridden, the
:not_found
atom can still be used to set the status to 404 as well as the new atom:actually_this_was_found
inflected from the reason phrase "Actually This Was Found".
Cowboy 手动指定 HTTP 响应代码并匹配指定的整数。
https://github.com/ninenines/cowboy/blob/1.0.x/src/cowboy_req.erl#L1318
允许二进制文件,但是这样做:
conn
|> put_status("451 Unavailable For Legal Reasons")
不会工作,因为插件只允许整数或已知原子。
这应该被认为是一个错误。您可以尝试在我链接的文件中获取 Cowboy 的拉取请求。
如果无法将 PR 合并到 Cowboy 中,也可以通过转换状态在 Cowboy 适配器的 Plug 中执行(这是一个幼稚的解决方案):
status = if (status == 451) do
"451 Unavailable For Legal Reasons"
else
status
end
在此文件中https://github.com/elixir-lang/plug/blob/master/lib/plug/adapters/cowboy/conn.ex#L33
另见 https://github.com/ninenines/cowboy/issues/965 and https://github.com/elixir-lang/plug/issues/451