使用Poison将编码映射为JSON,以便在Slack中使用。

11

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

"{\"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) - Dogbert
添加了一些代码以更好地说明我正在做什么。 - humdinger
这是Poison给我的:...你从代码中哪里得到了这个值? - Dogbert
这是我使用Poison编码时遇到的问题。具体来说,是在process_request_body函数中出现的。在Poison文档的用法部分下面的示例中,输出看起来就像这样:https://github.com/devinus/poison - humdinger
你想要访问哪种类型的端点,是传入的Webhook URL还是使用chat.postMessage API端点?前者接受application/json(但你应该确保设置了Content-type: application/json HTTP头),而后者不支持以这种方式POST JSON消息。 - Taylor Singletary
1
尝试对从Poison编码映射返回的对象使用JSON.parse,然后将其转换为JSON并发送到Slack API? - Indra Uprade
1个回答

4
看起来你的请求负载被JSON编码了两次: 首先它返回输出字符串{"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编码的字符串,就必须小心。再次提醒,我建议修复根本原因,但根据您的情况,这种解决方法也可能可行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接