使用 Poison 将映射编码为 JSON 以用于 Slack

Encoding map to JSON using Poison for use with Slack

我正在使用 Poison 将地图编码为 JSON,然后将其发送到 Slack API。这就是 Poison 给我的:

"{\"text\":\"changed readme fad996e98e04fd4a861840d92bdcbbcb1e1ec296\"}"

当我将其放入 JSON lint 时,它说它有效 JSON,但 Slack 响应 "invalid payload".

如果我将 JSON 改成这样

{"text":"changed readme fad996e98e04fd4a861840d92bdcbbcb1e1ec296"}

然后就可以了。有谁知道我哪里出了问题?我是否需要对编码的 JSON 进行额外处理,或者是否需要设置一些 header?

这是我的控制器

def create(conn, opts) do
    message = Message.create_struct(opts)
    response = Slack.Messages.send(message)

    case response do
      {:ok, data} ->
        render conn, json: Poison.encode!(data)
      {:error, reason} ->
        render conn, json: reason
    end
end

这是用于发送消息的库的一部分

defmodule Slack.Messages do

  def format_simple_message(map) do
    text = map.description <> " " <> map.commits
    message = %{text: text}
  end

  def post_to_slack(map) do
    Slack.post(:empty, map)
  end

  def send(map) do
    map
    |> format_simple_message
    |> post_to_slack
  end

end

还有我的HTTP毒化处理

defmodule Slack do
  use HTTPoison.Base

  @endpoint "http://url.com"

  def process_url() do
    @endpoint
  end

  def process_response_body(body) do
    body
    |> Poison.decode! # Turns JSON into map
  end

  def process_request_body(body) do
    body
    |> Poison.encode! # Turns map into JSON
  end
end

创建 JSON 的部分在最后一个块中。

您的请求负载似乎被 JSON 编码了两次: 起初它 returns 输出字符串 {"text":"..."} 然后那个字符串被再次编码。 JSON 不仅可以对对象进行编码,还可以对字符串进行编码,因此再次对上述内容进行编码将得到 "{\"text\":\"...\"}" 的输出。 即,包含对象的 JSON 编码表示的字符串。

但是,Slack API 需要 {"text": "..."} 形式的对象,而不是字符串 "..."。后者仍然有效 JSON,但就 API 而言,它不是有效请求。这就是为什么您返回“无效负载”错误的原因。

我不太确定对象在哪里被第二次编码。您上面的代码看起来没问题,但也许还有其他处理步骤不在这些代码片段中。我建议您仔细检查您的代码,寻找对某些数据应用两个 Poison.encode! 调用的路径。

然而,有一个解决方法——尽管我强烈建议您找到并修复根本原因,即双重 JSON 编码。在 process_request_body/1 中你可以匹配参数——如果它已经是一个字符串,跳过 Poison.encode!。为此,请使用以下代码:

def process_request_body(body) when is_binary(body), do: body
def process_request_body(body)
  body
  |> Poison.encode! # Turns map into JSON
end

这将逐字传递字符串并 JSON 编码任何其他内容。 但是,这可能很危险,因为字符串仍然是 JSON 编码的有效输入,因此如果您想通过 API 发送纯 JSON 编码的字符串,则必须小心。同样,我建议修复根本原因,但根据您的情况,此解决方法也可能可行。