檢視原始程式碼 Phoenix.Socket.Transport 行為 (Phoenix v1.7.14)
概述 Socket <-> Transport 通訊。
每個傳輸層,例如 WebSocket 和長輪詢,都必須與某個 Socket 互動。此模組定義該行為。
Phoenix.Socket
只是在多個通道上多工事件的一個可能的 Socket 實作。如果您實作這種行為,傳輸層將可以直接呼叫您的實作,而不會透過通道。
此模組也提供便利函數來實作傳輸層。
範例
以下是簡單的 echo 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 一樣 Mount 在您的終端點中
socket "/socket", EchoSocket, websocket: true, longpoll: true
您現在可以在 /socket/websocket
和 /socket/longpoll
底下與 Socket 互動。
自訂傳輸層
Socket 由傳輸層操作。當定義了某個傳輸層時,它通常會收到一個 Socket 模組,而當傳輸層等級發生特定事件時,將會呼叫該模組。
每當傳輸層收到一個新連線時,它應使用一個包含元資料的對應呼叫 connect/1
。不同的 Socket 可能需要不同的元資料。
如果接受了連線,傳輸層可以將連線移到另一個處理程序(如果需要),或繼續使用同一個處理程序。負責管理 Socket 的處理程序接著應呼叫 init/1
。
對於從用戶端接收的每則訊息,傳輸層必須在 Socket 上呼叫 handle_in/2
。對於傳輸層接收的每則資訊訊息,它應在 Socket 上呼叫 handle_info/2
。
傳輸層可以選擇實作 handle_control/2
來處理控制區段,例如 :ping
和 :pong
。
在終止時,必須呼叫 terminate/2
。可以將原因為 :closed
的特殊原子用於指定用戶端已終止連線。
開機
每當您的終端點啟動,它將自動對各個已列 Socket 呼叫 child_spec/1
並在終端點主管程式下啟動該規格。
由於端點開始套接字督導樹,因此任何自訂傳輸都必須在督導樹中於端點之後開始。
摘要
類型
回呼函數
@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}
- 停止通訊中繼端
僅在使用 WebSocket 時才支援控制框架。
options
包含一個 opcode
金鑰,此金鑰可能是 :ping
或 :pong
。
如果控制框架沒有 payload,則 payload 值會為 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
項與可以是任何條件的訊息的樹狀結構。內建 WebSocket 傳輸通訊支援 :text
與 :binary
opcode,而訊息必須永遠為 iodata。長輪詢僅支援 text 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
項與可以是任何條件的訊息的樹狀結構。內建 WebSocket 傳輸通訊支援 :text
與 :binary
opcode,而訊息必須永遠為 iodata。長輪詢僅支援 text opcode。
初始化套接字狀態。
此訊息必須在會實際執行通訊中繼端的程序中執行。
在終止時呼叫。
如果 reason
為 :closed
,則表示客戶端關閉了 socket。這被視為 :normal
的退出訊號,因此連結的程序將不會自動退出。有關退出訊號的更多詳細資訊,請參閱 Process.exit/2
。
函數
比對原點請求標頭與允許原點清單。
在適當時機,應該在連線前由傳輸機構呼叫。如果原始標頭符合允許的原始標頭、未傳送原始標頭,或者未設定原始標頭,則它將傳回指定的連線。
否則,將傳送 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
- 所有 trace context 標頭的清單:x_headers
- 所有前綴為「x-」的要求標頭清單:uri
- 從 conn 衍生的%URI{}
:user_agent
- 「user-agent」要求標頭的值
記錄傳輸請求。
可供產生連線的傳輸機構使用。