3

我正在编写 Elixir (1.8) + Plug_Cowboy (2.0.2) + Jason (1.1.2) 服务器。根据我从文档中获得的信息,一旦 Plug 解析器通过,我应该将所有内容都放在body_params. 问题是conn.body_params在我的情况下访问返回%Plug.Conn.Unfetched{aspect: :body_params}. 检查下面的代码:

defmodule Test.Router do
  use Plug.Router
  require Logger

  plug :match
  plug Plug.Parsers, parsers: [:json],
                     pass: ["application/json", "text/json"],
                     json_decoder: Jason
  plug :dispatch

  post "/test" do
    Logger.debug inspect(conn.body_params)
    conn
      |> put_resp_content_type("text/plain")
      |> send_resp(204, "Got it")
    end
end

知道发生了什么吗?

我对此进行了测试:

curl -H "Content-Type: text/json" -d "{one: 1, two: 2}" 127.0.0.1:8080/test

我曾尝试添加:urlencoded到解析器,或重新排列插件顺序,但无济于事。

4

1 回答 1

7

Plug.Parsers.JSON只处理application/json内容类型。这就是body_params没有填充的原因。您的测试 JSON 也是无效的 - 对象属性名称没有被引用。

curl -H "Content-Type: application/json" -d '{"one": 1, "two": 2}' 127.0.0.1:8080/test

指示它忽略那些没有定义解析器的类型的请求(例如在您的情况下)的pass:选项,而不是引发它通常会做的事情。添加该选项隐藏了错误。Plug.Parserstext/jsonUnsupportedMediaTypeError

您可能会发现它usePlug.Debugger在开发过程中很有用 - 它可以让您更好地了解在意外情况下发生的情况。

如果由于某种原因您需要能够解析非标准text/json类型的 JSON(例如,由于来自您无法控制的软件的请求),您可以为该类型定义一个新的解析器,该解析器只是包装Plug.Parsers.JSON并重写text/jsonapplication/json

defmodule WrongJson do
  def init(opts), do: Plug.Parsers.JSON.init(opts)

  def parse(conn, "text", "json", params, opts) do
    Plug.Parsers.JSON.parse(conn, "application", "json", params, opts)
  end

  def parse(conn, _type, _subtype, _params, _opts), do: {:next, conn}
end

然后将其添加到您的解析器列表中:

plug Plug.Parsers,
  parsers: [:json, WrongJson],
  json_decoder: Jason

现在text/json也将起作用。

于 2019-03-30T02:51:29.190 回答