【问题标题】:How to match params frontend to backend API如何将参数前端与后端 API 匹配
【发布时间】:2017-05-11 11:04:34
【问题描述】:

我目前正在使用 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

我们将不胜感激。

【问题讨论】:

  • 你能发布你的KegCopRAPI.Web.UserController.create函数吗?
  • 没问题,请稍等。
  • def create(conn, %{"user" =&gt; user_params}) 吗?
  • 尝试在session.js 中将api.post('/users', data) 更改为api.post('/users', {user: data})
  • @Dogbert 的回答比我输入的还要好。

标签: javascript reactjs elixir phoenix-framework


【解决方案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 })

我看到您也在其他一些函数中发送这样的数据,您还需要根据您在后端接受数据的方式相应地调整它们。

【讨论】:

    猜你喜欢
    • 2020-04-02
    • 2019-05-09
    • 2019-11-13
    • 2020-12-05
    • 2016-09-03
    • 2022-01-13
    • 2023-01-24
    • 1970-01-01
    • 2021-10-23
    相关资源
    最近更新 更多