【问题标题】:Encoding map to JSON using Poison for use with Slack使用 Poison 将映射编码为 JSON 以与 Slack 一起使用
【发布时间】:2016-11-19 18:16:48
【问题描述】:

我正在使用 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 的部分在最后一个块中。

【问题讨论】:

  • 能贴出相关控制器功能的源码吗?你可能打电话给json(conn, Poison.encode!(data))而不是json(conn, data)
  • 添加了一些代码,以便更好地了解我在做什么。
  • "这就是 Poison 给我的:..." 你是从代码中的什么地方得到这个值的?
  • 这来自我使用 Poison 进行编码的任何时候。具体来自 process_request_body。在 Poison 文档中,这就是他在用法部分下的示例中的输出:github.com/devinus/poison
  • 对从 Poison 编码映射到 JSON 的返回对象尝试 JSON.parse,然后将其发送到 slack API?

标签: elixir slack-api elixir-poison


【解决方案1】:

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

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

我不完全确定第二次编码对象的位置。您上面的代码看起来不错,但可能还有其他处理步骤不在那些代码 sn-ps 中。我建议您仔细检查您的代码,以找到将两个 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-24
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 2020-05-15
    • 2016-01-07
    • 1970-01-01
    相关资源
    最近更新 更多