11

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

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

当我将它放入 JSON lint 时,它说它是有效的 JSON,但 Slack 响应“无效负载”。

如果我将 JSON 更改为如下所示

{"text":"changed readme fad996e98e04fd4a861840d92bdcbbcb1e1ec296"}

然后它工作。有谁知道我哪里错了?我是否需要对编码的 JSON 进行额外处理,还是需要设置一些标头?

这是我的控制器

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

还有我的 HTTPoison 处理

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 的部分位于最后一个块中。

4

1 回答 1

4

您的请求有效负载似乎被 JSON 编码两次:首先它返回输出字符串{"text":"..."},然后该字符串再次被编码。JSON 不仅可以对对象进行编码,还可以对字符串进行编码,因此上述再次编码将给出"{\"text\":\"...\"}". 即,包含对象的 JSON 编码表示的字符串。

但是,Slack API 需要一个 form 对象{"text": "..."},而不是 string "..."。后者仍然是有效的 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 编码的字符串,则必须小心。同样,我建议修复根本原因,但根据您的情况,这种解决方法也可能是可行的。

于 2016-09-27T07:51:06.247 回答