我是Phoenix / Elixir的初学者,我正在尝试编写API以允许用户在我的应用程序中注册。
除非我尝试设置响应的HTTP状态代码,否则API端点将按预期工作。当我包含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
为什么会这样,我哪里出错?
答案 0 :(得分:7)
编辑截至2016年10月22日,现在可以在Plug master上实现。以下是文档的相关部分供参考:
自定义状态代码
Plug允许覆盖或添加状态代码,以允许新的代码不是由Plug或直接指定的 它的适配器。添加或覆盖状态代码是通过 混合
:plug
应用程序的配置。例如,到 覆盖404状态码的现有404原因短语
(默认情况下为“未找到”)并添加新的451状态代码,如下所示 可以指定config:config :plug, :statuses, %{ 404 => "Actually This Was Found", 451 => "Unavailable For Legal Reasons" }
由于此配置是特定于插件的,因此需要重新编译插件才能进行更改:这不会发生 自动,因为依赖关系不会自动重新编译时 他们的配置有所变 重新编译插件:
MIX_ENV=prod mix deps.compile plug
在许多函数中可以用来代替状态代码的原子是从 原因代码的原因短语。有了上面的配置, 以下将全部有效:
put_status(conn, :not_found) # 404 put_status(conn, :actually_this_was_found) # 404 put_status(conn, :unavailable_for_legal_reasons) # 451
即使重写了404,
:not_found
原子仍然可以 用于将状态设置为404以及新原子:actually_this_was_found
从原因短语中发现 “实际上这是找到的”。
牛仔手动指定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是不可能的,也可以通过转换状态在Plug for the Cowboy适配器中执行(这是一个天真的解决方案):
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和https://github.com/elixir-lang/plug/issues/451