You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Phoenix集成Pigeon FCM V1时元组转JSON报错,求简易解决方案

问题解决:Phoenix + Pigeon 2.0 FCM V1 元组序列化报错

错误原因

Jason编码器默认不支持元组类型的序列化,当代码尝试将包含{:token, "xxx"}元组的响应/通知数据通过Phoenix.Controller.json/2返回时,就会触发Protocol.UndefinedError。

简易解决方案

1. 手动将元组转换为Map(推荐)

在序列化前,把元组结构转为Jason支持的Map类型。比如如果原始通知或响应中包含{:token, my_token},直接转换为%{token: my_token}:

# 假设原始数据是包含元组的结构
raw_data = %{
  notification: {:token, my_token},
  response: pigeon_response
}

# 转换token元组为Map
formatted_data = %{
  raw_data
  | notification: %{token: elem(raw_data.notification, 1)}
}

# 再返回JSON
json(conn, formatted_data)

如果是批量处理包含多个元组的列表,可以用Enum.into/2:

tuple_list = [{:token, my_token}, {:title, "Hello"}]
map = Enum.into(tuple_list, %{})

2. 修正Pigeon消息构造方式

检查构造FCM V1消息的代码,Pigeon 2.0的FCM V1消息应该直接通过关键字参数赋值,而非传入元组。正确的构造方式示例:

message = Pigeon.FCM.V1.Message.new(
  token: my_token,
  data: %{"content" => "New notification"},
  notification: %Pigeon.FCM.V1.Notification{
    title: "Alert",
    body: "You have a new message"
  }
)

如果之前错误地将{:token, my_token}作为消息字段传入,修正为上述格式即可避免后续序列化问题。

3. 局部实现Tuple的Jason编码器(不推荐全局使用)

如果必须保留元组结构,可以在项目中为Tuple实现Jason编码器,但注意这会影响所有元组的序列化行为:

defimpl Jason.Encoder, for: Tuple do
  def encode({key, value}, opts) when is_atom(key) do
    Jason.Encode.encode(%{key => value}, opts)
  end

  def encode(tuple, opts) do
    # 其他元组转列表处理
    Tuple.to_list(tuple) |> Jason.Encode.encode(opts)
  end
end

关于Pigeon V2 + FCM V1 + Phoenix的使用情况

该组合是社区中常用的推送方案,有大量开发者在生产环境中使用,只要确保数据结构符合Jason序列化要求,就能稳定运行。

内容的提问来源于stack exchange,提问作者Sinc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:07:04