编写自定义插件,该插件可以处理并返回正文中格式错误的JSON的正确错误
我正在尝试编写一个插件,如果请求的JSON格式不正确,它将生成一个自定义错误,这在我们的场景中非常常见(因为我们在postman中使用变量。例如,有时值之外没有引号,这会导致格式不正确的JSON)。我得到的唯一帮助当然是无效的编写自定义插件,该插件可以处理并返回正文中格式错误的JSON的正确错误,json,parsing,elixir,phoenix-framework,plug,Json,Parsing,Elixir,Phoenix Framework,Plug,我正在尝试编写一个插件,如果请求的JSON格式不正确,它将生成一个自定义错误,这在我们的场景中非常常见(因为我们在postman中使用变量。例如,有时值之外没有引号,这会导致格式不正确的JSON)。我得到的唯一帮助当然是无效的 defmodule PogioApi.Plug.PrepareParse do import Plug.Conn @env Application.get_env(:application_api, :env) def init(opts) do o
defmodule PogioApi.Plug.PrepareParse do
import Plug.Conn
@env Application.get_env(:application_api, :env)
def init(opts) do
opts
end
def call(conn, opts) do
%{method: method} = conn
# TODO: check for PUT aswell
if method in ["POST"] and not(@env in [:test]) do
{:ok, body, _conn} = Plug.Conn.read_body(conn)
case Jason.decode(body) do
{:ok, _result} -> conn
{:error, _reason} ->
error = %{message: "Malformed JSON in the body"}
conn
|> put_resp_header("content-type", "application/json; charset=utf-8")
|> send_resp(400, Jason.encode!(error))
|> halt
end
else
conn
end
end
end
这条线
{:ok, body, _conn} = Plug.Conn.read_body(conn)
如何正确读取和解析正文。我知道在POST中,我们总是会得到format=JSON请求
问题:问题是正文,只能阅读一次。如果我以前在endpoint.ex文件中的自定义插件中阅读过body,那么Plug.Parses将无法找到body。请按以下顺序添加自定义body reader和自定义插件
plug Api.Plug.PrepareParse # should be called before Plug.Parsers
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
body_reader: {CacheBodyReader, :read_body, []}, # CacheBodyReader option is also needed
json_decoder: Phoenix.json_library()
定义一个
然后,您的自定义解析将准备就绪
defmodule Api.Plug.PrepareParse do
import Plug.Conn
@env Application.get_env(:application_api, :env)
@methods ~w(POST PUT PATCH PUT)
def init(opts) do
opts
end
def call(conn, opts) do
%{method: method} = conn
if method in @methods and not (@env in [:test]) do
case Plug.Conn.read_body(conn, opts) do
{:error, :timeout} ->
raise Plug.TimeoutError
{:error, _} ->
raise Plug.BadRequestError
{:more, _, conn} ->
# raise Plug.PayloadTooLargeError, conn: conn, router: __MODULE__
error = %{message: "Payload too large error"}
render_error(conn, error)
{:ok, "" = body, conn} ->
body = "{}" // otherwise error
update_in(conn.assigns[:raw_body], &[body | &1 || []])
{:ok, body, conn} ->
case Jason.decode(body) do
{:ok, _result} ->
update_in(conn.assigns[:raw_body], &[body | &1 || []])
{:error, _reason} ->
error = %{message: "Malformed JSON in the body"}
render_error(conn, error)
end
end
else
conn
end
end
def render_error(conn, error) do
conn
|> put_resp_header("content-type", "application/json; charset=utf-8")
|> send_resp(400, Jason.encode!(error))
|> halt
end
end
参考文献很少:
请说明您的问题是什么,以及具体失败的是什么(例如,您收到的错误消息等。)确定更新问题
defmodule Api.Plug.PrepareParse do
import Plug.Conn
@env Application.get_env(:application_api, :env)
@methods ~w(POST PUT PATCH PUT)
def init(opts) do
opts
end
def call(conn, opts) do
%{method: method} = conn
if method in @methods and not (@env in [:test]) do
case Plug.Conn.read_body(conn, opts) do
{:error, :timeout} ->
raise Plug.TimeoutError
{:error, _} ->
raise Plug.BadRequestError
{:more, _, conn} ->
# raise Plug.PayloadTooLargeError, conn: conn, router: __MODULE__
error = %{message: "Payload too large error"}
render_error(conn, error)
{:ok, "" = body, conn} ->
body = "{}" // otherwise error
update_in(conn.assigns[:raw_body], &[body | &1 || []])
{:ok, body, conn} ->
case Jason.decode(body) do
{:ok, _result} ->
update_in(conn.assigns[:raw_body], &[body | &1 || []])
{:error, _reason} ->
error = %{message: "Malformed JSON in the body"}
render_error(conn, error)
end
end
else
conn
end
end
def render_error(conn, error) do
conn
|> put_resp_header("content-type", "application/json; charset=utf-8")
|> send_resp(400, Jason.encode!(error))
|> halt
end
end