查看源代码 编写 Channels 客户端

Phoenix Channels 的客户端库已经存在于 多种语言 中,但如果你想自己编写一个,本指南可以帮助你入门。它也可能作为使用 WebSocket 客户端进行手动测试的指南。

概述

由于 WebSockets 是双向的,消息可以在任何时间以任何方向流动。因此,客户端通常使用回调来处理传入的消息,无论何时它们到来。

客户端必须至少加入一个主题才能开始发送和接收消息,并且可以使用同一个连接加入任意数量的主题。

连接

要建立与 Phoenix Channels 的 WebSocket 连接,首先请注意应用程序的 Endpoint 模块中的 socket 声明。例如,如果你看到:socket "/mobile", MyAppWeb.MobileSocket,则初始 HTTP 请求的路径为

[host]:[port]/mobile/websocket?vsn=2.0.0

传递 &vsn=2.0.0 指定 Phoenix.Socket.V2.JSONSerializer,它内置于 Phoenix 中,并期望以列表形式接收和返回消息。

你还需要包含 将 HTTP 请求升级到 WebSocket 连接的标准标头字段,或使用一个为你处理此操作的 HTTP 库;在 Elixir 中,mint_web_socket 是一个例子。

应用程序的套接字模块(在上例中为 MyAppWeb.MobileSocket.connect/3)中特定的 connect/3 函数可能期望或需要其他参数或标头。

消息格式

消息格式由为应用程序配置的序列化器决定。在这些示例中,假设使用 Phoenix.Socket.V2.JSONSerializer

客户端发送到 Phoenix Channel 的消息的一般格式如下

[join_reference, message_reference, topic_name, event_name, payload]
  • join_reference 也由客户端选择,也应该是一个唯一的值。它只需要在 "phx_join" 事件中发送;对于其他消息,它可以为 null。它用作来自服务器的 push 消息的消息引用,这意味着这些消息不是对特定客户端消息的回复。例如,想象一下类似“新用户刚刚加入聊天室”这样的内容。
  • message_reference 由客户端选择,应该是一个唯一的值。服务器将其包含在回复中,以便客户端知道回复是针对哪条消息的。
  • topic_name 必须是套接字端点已知的主题,并且客户端必须加入该主题才能在其上发送任何消息。
  • event_name 必须与服务器通道模块中的 handle_in 函数的第一个参数匹配。
  • payload 应该是一个映射,并作为该 handle_in 函数的第二个参数传递。

每个 Phoenix 应用程序都理解三个事件。

首先,phx_join 用于加入一个通道。例如,要加入 miami:weather 通道

["0", "0", "miami:weather", "phx_join", {"some": "param"}]

其次,phx_leave 用于离开一个通道。例如,要离开 miami:weather 通道

[null, "1", "miami:weather", "phx_leave", {}]

第三,heartbeat 用于维护 WebSocket 连接。例如

[null, "2", "phoenix", "heartbeat", {}]

heartbeat 消息仅在没有其他消息发送时才需要,并防止 Phoenix 关闭连接;确切的 :timeout 在应用程序的 Endpoint 模块中配置。

其他允许的消息取决于 Phoenix 应用程序。

例如,如果为 miami:weather 提供服务的 Channel 可以处理 report_emergency 事件

def handle_in("report_emergency", payload, socket) do
  MyApp.Emergencies.report(payload) # or whatever
  {:reply, :ok, socket}
end

...客户端可以发送

[null, "3", "miami:weather", "report_emergency", {"category": "sharknado"}]