AJAX Post 请求错误:“不能为空”,[验证::required] 在 POST 正文中发送 JSON 对象时
Posted
技术标签:
【中文标题】AJAX Post 请求错误:“不能为空”,[验证::required] 在 POST 正文中发送 JSON 对象时【英文标题】:AJAX Post request error: "can't be blank", [validation: :required] When sending JSON object in POST body 【发布时间】:2017-10-22 19:05:08 【问题描述】:当请求在OPTIONS "/products"
到达我的路由器时,我收到此错误
错误
14:45:33.433 [error] #PID<0.339.0> running Api.Router terminated
Server: 192.168.20.3:4000 (http)
Request: OPTIONS /products
** (exit) an exception was raised:
** (Poison.EncodeError) unable to encode value: :brand, "can't be blank", [validation: :required]
(poison) lib/poison/encoder.ex:383: Poison.Encoder.Any.encode/2
(poison) lib/poison/encoder.ex:259: anonymous fn/3 in Poison.Encoder.List.encode/3
(poison) lib/poison/encoder.ex:260: Poison.Encoder.List."-encode/3-lists^foldr/2-1-"/3
(poison) lib/poison/encoder.ex:260: Poison.Encoder.List.encode/3
(poison) lib/poison/encoder.ex:227: anonymous fn/4 in Poison.Encoder.Map.encode/3
(poison) lib/poison/encoder.ex:228: Poison.Encoder.Map."-encode/3-lists^foldl/2-0-"/3
(poison) lib/poison/encoder.ex:228: Poison.Encoder.Map.encode/3
(poison) lib/poison/encoder.ex:227: anonymous fn/4 in Poison.Encoder.Map.encode/3
显示在网络请求期间在前端捕获的错误的图像:
从上图来看,产品 JSON 对象似乎确实被发送了,因此由于某种原因它没有正确地将 http 帖子正文映射到 elixir 变更集。
连接日志:
Interactive Elixir (1.4.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> %
%Plug.Connadapter: Plug.Adapters.Cowboy.Conn, :..., assigns: %,
before_send: [], body_params: %,
cookies: %Plug.Conn.Unfetchedaspect: :cookies, halted: false,
host: "192.168.20.3", method: "OPTIONS", owner: #PID<0.339.0>, params: %,
path_info: ["products"], path_params: %, peer: 192, 168, 20, 3, 63793,
port: 4000,
private: %plug_route: #Function<1.14347947/1 in Api.Router.do_match/4>,
query_params: %, query_string: "", remote_ip: 192, 168, 20, 3,
req_cookies: %Plug.Conn.Unfetchedaspect: :cookies,
req_headers: ["host", "192.168.20.3:4000", "connection", "keep-alive",
"access-control-request-method", "POST", "origin", "http://evil.com/",
"user-agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/58.0.3029.110 Safari/
537.36",
"access-control-request-headers", "content-type,x-requested-with",
"accept", "*/*", "referer", "http://localhost:8081/debugger-ui",
"accept-encoding", "gzip, deflate, sdch",
"accept-language", "en-GB,en-US;q=0.8,en;q=0.6"], request_path: "/products",
resp_body: nil, resp_cookies: %,
resp_headers: ["cache-control", "max-age=0, private, must-revalidate"],
scheme: :http, script_name: [], secret_key_base: nil, state: :unset,
status: nil
%Api.Product__meta__: #Ecto.Schema.Metadata<:built, "products">, brand: nil,
description: nil, id: nil, image: nil, name: nil, numberOfVotes: nil,
rating: nil
router.ex
defmodule Api.Router do
use Plug.Router
if Mix.env == :dev do
use Plug.Debugger
end
plug :match
plug Plug.Parsers, parsers: [:json],
pass: ["application/json"],
json_decoder: Poison
plug :dispatch
get "/favicon.ico" do
# Api.Repo.getCategories(conn)
end
get "/categories/" do
Api.Repo.getCategories(conn)
end
options "/categories/" do
Api.Repo.getCategories(conn)
end
post "/products" do
Api.Repo.insertProduct(conn, conn.body_params)
end
options "/products" do
IO.puts inspect conn.body_params
Api.Repo.insertProduct(conn, conn.body_params)
end
get "/products" do
Api.Repo.insertProduct(conn, conn.body_params)
end
end
在 repo.ex 中
def insertProduct(conn, product) do
IO.inspect(conn)
changeset = Api.Product.changeset(%Api.Product, product)
errors = changeset.errors
valid = changeset.valid?
case insert(changeset) do
:ok, product ->
conn
|> put_resp_content_type("application/json")
|> send_resp(200, Poison.encode!(%
successs: "success"
))
:error, changeset ->
conn
|> put_resp_content_type("application/json")
|> send_resp(500, Poison.encode!(%
failure: changeset
))
end
end
product.ex
defmodule Api.Product do
use Ecto.Schema
@derive Poison.Encoder, only: [:name, :brand, :description, :image, :rating, :numberOfVotes]
schema "products" do
field :name, :string
field :brand, :string
field :description, :string
field :image, :string
field :rating, :integer
field :numberOfVotes, :integer
end
def changeset(product, params \\ %) do
product
|> Ecto.Changeset.cast(params, [:name, :brand, :description, :image, :rating, :numberOfVotes])
|> Ecto.Changeset.validate_required([:name, :description, :brand])
end
end
顺便说一句-origin is evil.com because of a browser plugin I use to enable CORS
【问题讨论】:
insertProduct
函数体的第一行是IO.puts conn
。问题是 conn
是一个结构,而 IO.puts/2
接受一个字符串参数。如果您尝试调试字符串或字符数据以外的其他内容,则可以将其切换为 IO.inspect
。
@stevelove 太棒了,谢谢你帮了大忙。已更新问题。
答案就在错误中:expected params to be a map, got: %Api.Product...
。可能在这里:lib/api/product.ex:16
。当函数期望您传递映射时,您似乎正在调用 Ecto 的 cast
函数之一(即%Api.Product
),即%
。
@stevelove 是的,谢谢。会让它期待%Api.Product...
我认为问题出在 repo.ex 中,您正在从 params
创建一个 Product 结构并将其发送到 Api.Product.changeset
。直接发送params
。
【参考方案1】:
在 react native 中使用的一些 javascript 全局常量允许网络请求显示在 chrome 开发者控制台中:
GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest
似乎自己也弄乱了网络请求。一旦我摆脱了那个代码,它就会将POST
ed 产品插入到数据库中。
感谢 cmets 帮助我度过了难关。
【讨论】:
以上是关于AJAX Post 请求错误:“不能为空”,[验证::required] 在 POST 正文中发送 JSON 对象时的主要内容,如果未能解决你的问题,请参考以下文章
错误:“CSRF 验证失败。请求中止。”在 Django 中使用 jquery ajax 时