查看源代码 Phoenix.Socket.Transport 行为 (Phoenix v1.7.14)
概述 Socket <-> Transport 通信。
每个传输,例如 WebSockets 和长轮询,都必须与套接字交互。该模块定义了这种行为。
Phoenix.Socket
只是套接字的一种可能的实现,它通过多个通道复用事件。如果你实现此行为,则传输可以直接调用你的实现,无需通过通道。
该模块还提供用于实现传输的便捷函数。
示例
这是一个简单的回声套接字实现
defmodule EchoSocket do
@behaviour Phoenix.Socket.Transport
def child_spec(opts) do
# We won't spawn any process, so let's ignore the child spec
:ignore
end
def connect(state) do
# Callback to retrieve relevant data from the connection.
# The map contains options, params, transport and endpoint keys.
{:ok, state}
end
def init(state) do
# Now we are effectively inside the process that maintains the socket.
{:ok, state}
end
def handle_in({text, _opts}, state) do
{:reply, :ok, {:text, text}, state}
end
def handle_info(_, state) do
{:ok, state}
end
def terminate(_reason, _state) do
:ok
end
end
它可以像任何其他套接字一样挂载到你的端点中
socket "/socket", EchoSocket, websocket: true, longpoll: true
你现在可以在 /socket/websocket
和 /socket/longpoll
下与套接字交互。
自定义传输
套接字由传输操作。当定义传输时,它通常会接收一个套接字模块,并且当传输级别发生某些事件时,将调用该模块。
每当传输接收到新的连接时,它都应该使用元数据的映射调用 connect/1
回调。不同的套接字可能需要不同的元数据。
如果连接被接受,传输可以将连接移动到另一个进程(如果需要)或继续使用相同的进程。负责管理套接字的进程应该调用 init/1
。
对于从客户端接收到的每条消息,传输必须调用套接字上的 handle_in/2
。对于传输接收到的每条信息消息,它都应该调用套接字上的 handle_info/2
。
传输可以选择实现 handle_control/2
来处理控制帧,例如 :ping
和 :pong
。
在终止时,必须调用 terminate/2
。可以使用带有原因 :closed
的特殊原子来指定客户端终止了连接。
启动
每当你的端点启动时,它将自动调用每个列出的套接字上的 child_spec/1
,并在端点主管下启动该规范。
由于套接字监管树由端点启动,因此任何自定义传输都必须在监管树中的端点之后启动。
摘要
函数
检查 origin 请求头是否与允许的来源列表匹配。
检查 Websocket 子协议请求头是否与允许的子协议匹配。
如果启用了代码重新加载,则运行代码重新加载器。
从 conn
中提取连接信息并返回一个映射。
记录传输请求。
类型
回调
@callback child_spec(keyword()) :: :supervisor.child_spec() | :ignore
返回用于套接字管理的子规范。
这仅在每个套接字上调用一次,无论传输数量多少,它应该负责设置任何专门由套接字使用的进程结构,而与传输无关。
每个套接字连接都由传输启动,并且控制套接字的进程可能属于传输。但是,一些套接字会生成新的进程,例如 Phoenix.Socket
会生成通道,这使得能够启动与套接字关联的监管树。
它从端点接收套接字选项,例如
socket "/my_app", MyApp.Socket, shutdown: 5000
意味着将调用 child_spec([shutdown: 5000])
。
:ignore
表示此套接字不需要子规范。
连接到套接字。
传输传递一个元数据映射,套接字返回 {:ok, state}
、{:error, reason}
或 :error
。状态必须由传输存储并在所有未来的操作中返回。当返回 {:error, reason}
时,一些传输(例如 WebSockets)允许通过自定义 :error_handler
根据 reason
自定义响应。
此函数用于授权目的,它可能在有效运行套接字的进程之外调用。
在默认的 Phoenix.Socket
实现中,元数据期望以下键
:endpoint
- 应用程序端点:transport
- 传输名称:params
- 连接参数:options
- 传输选项的关键字列表,通常由开发人员在配置传输时提供。它必须包含一个带有序列化程序列表及其要求的:serializer
字段
@callback drainer_spec(keyword()) :: :supervisor.child_spec() | :ignore
返回用于终止套接字的子规范。
这是一个在监管树中较晚启动的进程,其特定目标是在应用程序关闭时排空连接。
与 child_spec/1
类似,它从端点接收套接字选项。
@callback handle_control( {message :: term(), opts :: keyword()}, state() ) :: {:ok, state()} | {:reply, :ok | :error, {opcode :: atom(), message :: term()}, state()} | {:stop, reason :: term(), state()}
处理传入的控制帧。
消息表示为 {payload, options}
。它必须返回以下之一
{:ok, state}
- 继续套接字,无回复{:reply, status, reply, state}
- 继续套接字并进行回复{:stop, reason, state}
- 停止套接字
仅在使用 WebSockets 时支持控制帧。
options
包含一个 opcode
键,它将是 :ping
或 :pong
。
如果控制帧没有有效负载,则有效负载值将为 nil
。
@callback handle_in( {message :: term(), opts :: keyword()}, state() ) :: {:ok, state()} | {:reply, :ok | :error, {opcode :: atom(), message :: term()}, state()} | {:stop, reason :: term(), state()}
处理传入的套接字消息。
消息表示为 {payload, options}
。它必须返回以下之一
{:ok, state}
- 继续套接字,无回复{:reply, status, reply, state}
- 继续套接字并进行回复{:stop, reason, state}
- 停止套接字
reply
是一个元组,包含一个 opcode
原子和一个消息,该消息可以是任何项。内置的 WebSockets 传输支持 :text
和 :binary
opcode,并且消息必须始终是 iodata。长轮询仅支持文本 opcode。
@callback handle_info(message :: term(), state()) :: {:ok, state()} | {:push, {opcode :: atom(), message :: term()}, state()} | {:stop, reason :: term(), state()}
处理信息消息。
消息是一个项。它必须返回以下之一
{:ok, state}
- 继续套接字,无回复{:push, reply, state}
- 继续套接字并进行回复{:stop, reason, state}
- 停止套接字
reply
是一个元组,包含一个 opcode
原子和一个消息,该消息可以是任何项。内置的 WebSockets 传输支持 :text
和 :binary
opcode,并且消息必须始终是 iodata。长轮询仅支持文本 opcode。
初始化套接字状态。
这必须从将有效操作套接字的进程中执行。
在终止时调用。
如果 reason
是 :closed
,则意味着客户端关闭了套接字。这被认为是 :normal
退出信号,因此链接的进程不会自动退出。有关退出信号的更多详细信息,请参阅 Process.exit/2
。
函数
检查 origin 请求头是否与允许的来源列表匹配。
应该在适当的情况下由传输在连接之前调用。如果 origin 标头与允许的来源匹配,则没有发送 origin 标头或没有配置 origin,它将返回给定的连接。
否则,将发送 403 禁止响应,并将连接停止。如果连接已停止,它将是一个空操作。
检查 Websocket 子协议请求头是否与允许的子协议匹配。
应该在适当的情况下由传输在连接之前调用。如果 sec-websocket-protocol 标头与允许的子协议匹配,它将设置 sec-websocket-protocol 响应标头并返回给定的连接。如果没有发送 sec-websocket-protocol 标头,它将返回给定的连接。
否则,将发送 403 禁止响应,并将连接停止。如果连接已停止,它将是一个空操作。
如果启用了代码重新加载,则运行代码重新加载器。
从 conn
中提取连接信息并返回一个映射。
键从可选的传输选项 :connect_info
中检索。此功能是特定于传输的。有关更多信息,请参阅你的传输文档。
支持的键为
:peer_data
-Plug.Conn.get_peer_data/1
的结果:trace_context_headers
- 所有跟踪上下文标头的列表:x_headers
- 所有以“x-”为前缀的请求标头的列表:uri
- 从 conn 派生的%URI{}
:user_agent
- “user-agent” 请求标头的值
记录传输请求。
适用于生成连接的传输。