我目前正在使用Elixir编写的phx API,我可以使用Postman成功创建一个帐户。但是,当我尝试使用React.js前端创建一个帐户时,我在控制台中获得了以下堆栈跟踪。
[debug] Simple CORS request from Origin 'http://localhost:3000' is allowed
[debug] Processing with KegCopRAPI.Web.UserController.create/2
Parameters: %{"email" => "diana@example.com", "password" => "[FILTERED]", "username" => "diana"}
Pipelines: [:api]
[info] Sent 400 in 1ms
[debug] ** (Phoenix.ActionClauseError) could not find a matching KegCopRAPI.Web.UserController.create clause
to process request. This typically happens when there is a
parameter mismatch but may also happen when any of the other
action arguments do not match. The request parameters are:
%{"email" => "diana@example.com", "password" => "password", "username" => "diana"}
(kegcopr_api) lib/kegcopr_api/web/controllers/user_controller.ex:17: KegCopRAPI.Web.UserController.create(%Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<1.33581574/1 in Plug.Logger.call/2>, #Function<0.72433304/1 in Phoenix.LiveReloader.before_send_inject_reloader/2>], body_params: %{"email" => "diana@example.com", "password" => "password", "username" => "diana"}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "POST", owner: #PID<0.413.0>, params: %{"email" => "diana@example.com", "password" => "password", "username" => "diana"}, path_info: ["api", "users"], path_params: %{}, peer: {{127, 0, 0, 1}, 58421}, port: 4000, private: %{KegCopRAPI.Web.Router => {[], %{}}, :guardian_default_claims => {:error, %CaseClauseError{term: {:error, {:badarg, ["null"]}}}}, :guardian_default_resource => nil, :phoenix_action => :create, :phoenix_controller => KegCopRAPI.Web.UserController, :phoenix_endpoint => KegCopRAPI.Web.Endpoint, :phoenix_format => "json", :phoenix_layout => {KegCopRAPI.Web.LayoutView, :app}, :phoenix_pipelines => [:api], :phoenix_router => KegCopRAPI.Web.Router, :phoenix_view => KegCopRAPI.Web.UserView, :plug_session_fetch => #Function<1.131660147/1 in Plug.Session.fetch_session/1>}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies}, req_headers: [{"host", "localhost:4000"}, {"connection", "keep-alive"}, {"content-length", "70"}, {"accept", "application/json"}, {"origin", "http://localhost:3000"}, {"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"}, {"authorization", "Bearer: null"}, {"content-type", "application/json"}, {"referer", "http://localhost:3000/signup"}, {"accept-encoding", "gzip, deflate, br"}, {"accept-language", "en-US,en;q=0.8"}], request_path: "/api/users", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "ka5l96ctaijuthp39krkbg597n4r75lj"}, {"access-control-allow-origin", "*"}, {"access-control-expose-headers", ""}, {"access-control-allow-credentials", "true"}, {"vary", ""}], scheme: :http, script_name: [], secret_key_base: "fIEpvi5ujSQEKgmkRpt83KiLPq068sSmvFKlWFZyNpi3nkNmUtYO24Em6cXIUblZ", state: :unset, status: nil}, %{"email" => "diana@example.com", "password" => "password", "username" => "diana"})
(kegcopr_api) lib/kegcopr_api/web/controllers/user_controller.ex:1: KegCopRAPI.Web.UserController.action/2
(kegcopr_api) lib/kegcopr_api/web/controllers/user_controller.ex:1: KegCopRAPI.Web.UserController.phoenix_controller_pipeline/2
(kegcopr_api) lib/kegcopr_api/web/endpoint.ex:1: KegCopRAPI.Web.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:277: Phoenix.Router.__call__/1
(kegcopr_api) lib/kegcopr_api/web/endpoint.ex:1: KegCopRAPI.Web.Endpoint.plug_builder_call/2
(kegcopr_api) lib/plug/debugger.ex:123: KegCopRAPI.Web.Endpoint."call (overridable 3)"/2
(kegcopr_api) lib/kegcopr_api/web/endpoint.ex:1: KegCopRAPI.Web.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /opt/elixir/kegcopr_api/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
我注意到我需要更改React.js前端的输入值以匹配API的已接受参数。
可以找到前端here。我相信需要更新的文件是 src / components / Input / index.js ,但我知道这是错误的。
// @flow
import React from 'react';
type Props = {
input: Object,
label?: string,
type?: string,
placeholder?: string,
style?: Object,
meta: Object,
}
const Input = ({ input, label, type, placeholder, style, meta }: Props) =>
<div style={{ marginBottom: '1rem' }}>
{label && <label htmlFor={input.name}>{label}</label>}
<input
{...input}
type={type}
placeholder={placeholder}
className="form-control"
style={style && style}
/>
{meta.touched && meta.error &&
<div style={{ fontSize: '85%', color: 'rgb(255,59,48)' }}>{meta.error}</div>
}
</div>;
export default Input;
user_controller.ex
def create(conn, %{"user" => user_params}) do
# with {:ok, %User{} = user} <- Accounts.create_user(user_params) do
changeset = User.registration_changeset(%User{}, user_params)
case Repo.insert(changeset) do
{:ok, user} ->
new_conn = Guardian.Plug.api_sign_in(conn, user, :access)
jwt = Guardian.Plug.current_token(new_conn)
# conn
# |> put_status(:created)
# |> put_resp_header("location", user_path(conn, :show, user))
# |> render("show.json", user: user)
new_conn
|> put_status(:created)
|> render(KegCopRAPI.SessionView, "show.json", user: user, jwt: jwt)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(KegCopRAPI.ChangesetView, "error.json", changeset: changeset)
end
end
非常感谢任何和所有帮助。
答案 0 :(得分:1)
您从React发送顶级表单的字段,但在后端控制器中,您从"user"
键内部获取数据。您需要将React发送的数据放在user
密钥下。在:
export function signup(data, router) {
return dispatch => api.post('/users', data)
.then((response) => {
setCurrentUser(dispatch, response);
dispatch(reset('signup'));
router.transitionTo('/');
});
}
变化:
api.post('/users', data)
为:
api.post('/users', { user: data })
我发现您在其他一些功能中也会发送这样的数据,您需要根据接受后端数据的方式相应地调整它们。