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
相关产品推荐
相关产品推荐

