檢視原始碼 Phoenix.Endpoint 行為 (Phoenix v1.7.14)
定義 Phoenix 終端點。
終端點是 Web 應用程式中所有請求的開始點。它也是應用程式提供給後端 Web 伺服器的介面。
大致上,終端點有三個責任
提供包覆器,作為監督樹的一部分,來啟動和停止終端點
定義一個初始的 plug 管線,供請求通過
為你的應用程式主機特定 Web 設定
終端點
終端點僅是一個模組,在 Phoenix.Endpoint
的協助下定義。如果你已使用 mix phx.new
產生器,終端點將會作為應用程式的一部分自動產生
defmodule YourAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :your_app
# plug ...
# plug ...
plug YourApp.Router
end
終端點必須明確地作為應用程式監督樹的一部分啟動。在已產生的應用程式中,終端點會預設加入監督樹。終端點可以依下列方式加入監督樹
children = [
YourAppWeb.Endpoint
]
終端點設定
所有終端點都在應用程式環境中設定。例如
config :your_app, YourAppWeb.Endpoint,
secret_key_base: "kjoy3o1zeidquwy1398juxzldjlksahdk3"
終端點設定分為兩種類別。編譯時期設定意指設定會在編譯期間讀取,且在執行階段變更沒有作用。編譯時期設定主要與錯誤處理有關。
執行階段設定則是會在應用程式啟動期間或啟動後存取,且可以透過 config/2
函式讀取
YourAppWeb.Endpoint.config(:port)
YourAppWeb.Endpoint.config(:some_config, :default_value)
編譯時期設定
編譯時期設定可以在 config/dev.exs
、config/prod.exs
等等設定,但對 config/runtime.exs
沒有作用
:code_reloader
- 當true
,啟用程式重新載入功能。有關程式重新載入組態選項清單,請參閱Phoenix.CodeReloader.reload/1
。請記住程式重新載入是基於檔案系統,因此不可能同時執行同一個應用程式的兩個執行個體,且同時在開發中重新載入程式,因為它們會彼此競賽,而只有一個會有效地重新編譯檔案。在這種情況下,請調整您的設定檔,使其僅在一個應用程式中啟用程式重新載入,或設定 MIX_BUILD 環境變數,以提供不同的建置目錄:debug_errors
- 當true
,使用Plug.Debugger
功能來偵錯應用程式中的失敗。建議僅在開發期間將其設定為true
,因為它允許在偵錯期間列出應用程式原始碼。預設為false
:force_ssl
- 確保從來不會透過 HTTP 傳送任何資料,總是重新導向到 HTTPS。它預期有一份選項清單,這些選項會傳送到Plug.SSL
。預設會在 HTTPS 要求中設定「strict-transport-security」標頭,強制瀏覽器總是使用 HTTPS。如果傳送了一份不安全的請求 (HTTP),它會重新導向到 HTTPS 版本,使用在:url
組態中指定的:host
。若要動態重新導向到目前的請求host
,請將:force_ssl
組態中的:host
設定為nil
執行時期組態
以下組態可以設定在 config/dev.exs
、config/prod.exs
等等,以及 config/runtime.exs
中。通常,如果您需要使用系統環境變數組態它們,請在 config/runtime.exs
中設定它們。這些選項也可以在您的監督樹中啟動終端機時設定,例如 {MyApp.Endpoint, options}
。
:adapter
- 使用哪個網頁伺服器介面來提供網頁請求。請參閱下方的「介面組態」區段:cache_static_manifest
- 一個 json 清單檔路徑,其中包含靜態檔案及其摘要版本。這通常設定為「priv/static/cache_manifest.json」,這個檔案是mix phx.digest
自動產生的。它可以是:包含檔案系統路徑的字串,或包含應用程式名稱和該應用程式中的路徑的組元。:cache_static_manifest_latest
- 指向其摘要版本之靜態檔案的映射。這會在開機時從cache_static_manifest
中自動載入。但是,如果您有自己的靜態處理機制,您可能希望明確設定此值。這是由如LiveView
之類的專案用來偵測客戶端是在所有資產的最新版本上執行。:cache_manifest_skip_vsn
- 當為 true 時,在產生靜態資產的路徑時會略過附加的查詢字串 "?vsn=d"。此查詢字串由Plug.Static
用來設定長到期日,因此,您應僅在不使用Plug.Static
來提供資產的情況下將此選項設定為 true(例如,如果您使用的是 CDN)。如果您要設定此選項,您也應考慮將--no-vsn
傳遞給mix phx.digest
。預設為false
。:check_origin
- 設定傳輸的預設:check_origin
設定。有關選項,請參閱socket/3
。預設為true
。:secret_key_base
- 用作產生加密和簽署資料的秘密之基本秘密金鑰。例如,預設情況下會簽署 cookie 和權杖,但它們也可以依需要進行加密。預設為nil
,因為必須為每個應用程式設定秘鑰:server
- 當為true
時,在端點監督樹狀結構啟動時啟動網路伺服器。預設為false
。mix phx.server
工作會自動將此設定為true
:url
- 針對整個應用程式產生 URL 的設定。接受:host
、:scheme
、:path
和:port
選項。除了:path
之外所有金鑰都可以在執行時期變更。預設為[host: "localhost", path: "/"]
:port
選項需要整數或字串。:host
選項需要字串。:scheme
選項接受"http"
和"https"
值。預設值從頂層:http
或:https
選項推斷。這在將 Phoenix 託管在負載平衡器或反向代理並在那裡終止 SSL 時很有用。:path
選項可用於覆寫根路徑。當將 Phoenix 託管在具有 URL 重寫規則的反向代理後面時很有用:static_url
- 產生靜態檔案 URL 的設定。如果沒有提供任何選項,它會回退到url
。接受與url
相同的選項:watchers
- 伺服器運作時的一組監控器。它需要包含可執行檔及其參數的元組清單。監控器保證會在應用程式目錄中執行,但僅限於伺服器已啟用的時候(除非:force_watchers
設定為true
)。例如,當伺服器啟動時,下方的偵測器會執行 webpack 建置工具的「watch」模式。你可以將其設定為任何你想要的建置工具或指令[ node: [ "node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch", "--watch-options-stdin" ] ]
清單結尾可以用
:cd
和:env
選項自訂要監控的對象[node: [..., cd: "assets", env: [{"TAILWIND_MODE", "watch"}]]]
偵測器也可以是將被適時呼叫的模組-函式-參數元組
[another: {Mod, :fun, [arg1, arg2]}]
:force_watchers
- 如果為true
,會強制你的偵測器在:server
選項設定為false
時啟動。:live_reload
- 即時重新載入選項的設定。設定需要一個:patterns
選項,選項應為要監控的檔案模式清單。當這些檔案變更時,它會觸發重新載入。live_reload: [ url: "ws://127.0.0.1:4000", patterns: [ ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$", ~r"lib/app_web/(live|views)/.*(ex)$", ~r"lib/app_web/templates/.*(eex)$" ] ]
:pubsub_server
- 在通道中和經由 Endpoin 廣播函式中要使用的 PubSub 伺服器。PubSub 伺服器通常在你的監督樹中啟動。:render_errors
- 每當應用程式出現錯誤時負責呈現範本。例如,如果應用程式在 HTML 請求期間發生 500 錯誤而崩潰,將會在提供給:render_errors
的檢視中呼叫render("500.html", assigns)
。可以提供一個:formats
清單,為每個格式指定一個模組以處理錯誤呈現。範例[formats: [html: MyApp.ErrorHTML], layout: false, log: :debug]
:log_access_url
- 伺服器啟動後記錄存取 URL
請注意,你也可以將你自己的設定儲存在 Phoenix.Endpoint 中。例如,Phoenix LiveView 預期在 :live_view
鍵下有它自己的設定。在這種情況下,你應參閱相關專案的說明文件。
轉接設定
Phoenix 允許你選擇要使用哪個網路伺服器轉接器。透過 phx.new
Mix 工作建立的新產生應用程式使用 Bandit
網路伺服器和 Bandit.PhoenixAdapter
轉接器。如果未透過 adapter
選項另行指定,Phoenix 會回歸到 Phoenix.Endpoint.Cowboy2Adapter
以維持與 Phoenix 1.7.8 之前產生的應用程式的向下相容性。
這兩個轉接器可以使用下列兩個頂層選項以類似的方式設定
:http
- 對 HTTP 伺服器的設定。接受Bandit
或Plug.Cowboy
所定義的選項(依您選擇的轉接器而定)。預設為false
:https
- 對 HTTPS 伺服器的設定。接受Bandit
或Plug.Cowboy
所定義的選項(依您選擇的轉接器而定)。預設為false
此外,也可以透過以下頂層選項來設定 Cowboy 網路伺服器的連線中止機制(這對 Bandit 來說並非必要,因為它的連線中止機制是內建的)
:drainer
- 一個 drainer 程序會在應用程式關閉時等待所有正在進行的請求完成。它接受Plug.Cowboy.Drainer
所定義的:shutdown
和:check_interval
選項。注意,中止機制不會終止任何現有的連線,它只會等待它們完成。在呼叫這個中止機制之前,通訊端連線會執行它們自己的中止機制。這是因為通訊端會記錄狀態且可以進行順利通知,這讓我們得以在更長的一段時間內調整它們。詳情請參考socket/3
的文件
終端 API
在上一節中,我們已經使用 config/2
函數,它會自動在您的終端中產生。以下是您的終端中會自動定義的所有函數清單
用於處理路徑和 URL:
struct_url/0
、url/0
、path/1
、static_url/0
、static_path/1
和static_integrity/1
用於收集終端執行位址和連接埠的執行時期資訊:
server_info/1
用於頻道廣播:
broadcast/3
、broadcast!/3
、broadcast_from/4
、broadcast_from!/4
、local_broadcast/3
和local_broadcast_from/4
用於設定:
start_link/1
、config/2
和config_change/2
根據
Plug
行為所需:Plug.init/1
和Plug.call/2
摘要
回呼函數
在指定topic
中廣播一個msg
訊息,格式為event
,對象為所有節點。
在指定topic
中廣播一個msg
訊息,格式為event
,對象為所有節點。
在指定topic
中,從指定from
廣播一個msg
訊息,格式為event
,對象為所有節點。
在指定topic
中,從指定from
廣播一個msg
訊息,格式為event
,對象為所有節點。
使用key存取終端機設定。
在應用程式更新時重新載入終端機設定。
從:url設定中傳回host。
在目前的節點中,使用指定topic
,廣播一個msg
訊息,格式為event
。
在目前的節點中,從指定from
,廣播一個msg
訊息,格式為event
,對象為所有節點。
將路由導入此終端機時,產生相關資訊。
從:url設定中傳回script name。
傳回server執行的位址和埠。
啟動endpoint監督工作樹。
在priv/static
中產生靜態檔案的完整性雜湊。
產生包含static_path
和static_integrity
的二元組。
在priv/static
中產生靜態檔案的路由。
產生不含任何路徑資訊的靜態URL。
產生endpoint的基本URL,但需為URI
結構。
讓呼叫者訂閱指定的topic。
讓呼叫者取消訂閱指定的topic。
產生不含任何路徑資訊的endpoint基本URL。
類型
回呼
在指定topic
中廣播一個msg
訊息,格式為event
,對象為所有節點。
在指定topic
中廣播一個msg
訊息,格式為event
,對象為所有節點。
發生錯誤時引發例外。
在指定topic
中,從指定from
廣播一個msg
訊息,格式為event
,對象為所有節點。
在指定topic
中,從指定from
廣播一個msg
訊息,格式為event
,對象為所有節點。
發生錯誤時引發例外。
使用key存取終端機設定。
在應用程式更新時重新載入終端機設定。
@callback host() :: String.t()
從:url設定中傳回host。
在目前的節點中,使用指定topic
,廣播一個msg
訊息,格式為event
。
在目前的節點中,從指定from
,廣播一個msg
訊息,格式為event
,對象為所有節點。
將路由導入此終端機時,產生相關資訊。
@callback script_name() :: [String.t()]
從:url設定中傳回script name。
@callback server_info(Plug.Conn.scheme()) :: {:ok, {:inet.ip_address(), :inet.port_number()} | :inet.returned_non_ip_address()} | {:error, term()}
傳回server執行的位址和埠。
@callback start_link(keyword()) :: Supervisor.on_start()
啟動endpoint監督工作樹。
啟動端點組態快取,以及可能用來處理請求的伺服器。
在priv/static
中產生靜態檔案的完整性雜湊。
產生包含static_path
和static_integrity
的二元組。
在priv/static
中產生靜態檔案的路由。
@callback static_url() :: String.t()
產生不含任何路徑資訊的靜態URL。
@callback struct_url() :: URI.t()
產生endpoint的基本URL,但需為URI
結構。
讓呼叫者訂閱指定的topic。
請參閱 Phoenix.PubSub.subscribe/3
以取得選項。
讓呼叫者取消訂閱指定的topic。
@callback url() :: String.t()
產生不含任何路徑資訊的endpoint基本URL。
函數
檢查Endpoint的網路伺服器是否已設定啟動。
otp_app
- 執行端點的 OTP 應用程式,例如:my_app
endpoint
- 端點模組,例如MyAppWeb.Endpoint
範例
iex> Phoenix.Endpoint.server?(:my_app, MyAppWeb.Endpoint)
true
為socket
定義一個websocket/longpoll掛載點。
他會預期有一個 path
、一個 socket
模組和一組選項。Socket 模組通常會使用 Phoenix.Socket
定義。
內建支援 websocket 和 longpolling 連線。
選項
:websocket
- 控制 websocket 設定。預設為true
。可以設為 false 或關鍵字清單選項。有關完整清單,請參閱 「一般設定」 和 「WebSocket 設定」:longpoll
- 控制 longpoll 設定。預設為false
。可以設為 true 或關鍵字清單選項。有關完整清單,請參閱 「一般設定」 和 「Longpoll 設定」:drainer
- 關鍵字清單或自訂 MFA 函數,回傳關鍵字清單,例如{MyAppWeb.Socket, :drainer_configuration, []}
設定如何在應用程式關閉時排空 socket。目標是通知所有頻道 (和 LiveView) 用戶端重新連線。支援的選項有
:batch_size
- 每個批次要一次通知多少用戶端。預設值為 10000。:batch_interval
- 給定一個批次結束的時間 (毫秒)。預設值為 2000 毫秒。:shutdown
- 排空所有批次允許的最大時間 (毫秒)。預設值為 30000 毫秒。
例如,如果你有 15 萬個連線,預設值會將它們分割成 15 個批次,每個批次有 1 萬個連線。在開始下一個批次之前,每個批次會間隔 2000 毫秒。在這個情況下,我們會在低於最大關閉時間 30000 毫秒內完成所有事情。因此,隨著你增加連線數,請記得調整相對應的關閉時間。最後,在 socket 排空器執行之後,較低層的 HTTP/HTTPS 連線排空器仍會執行,並套用至所有連線。設為
false
以停用排空。
你也可以在 use Phoenix.Socket
中傳入下方的選項。於此處指定的數值會覆寫 use Phoenix.Socket
中的數值。
範例
socket "/ws", MyApp.UserSocket
socket "/ws/admin", MyApp.AdminUserSocket,
longpoll: true,
websocket: [compress: true]
路徑參數
可以在路徑中包含變數,而這些變數可以在傳遞到 socket 的 params
中使用。
socket "/ws/:user_id", MyApp.UserSocket,
websocket: [path: "/project/:project_id"]
一般設定
下方的設定可以同時使用於 :websocket
和 :longpoll
鍵。
:path
- 這是傳輸層的路徑。其預設值將是傳輸層名稱(「/websocket」或「/longpoll」):serializer
- 訊息的序列化清單。更多資訊請參閱Phoenix.Socket
。:transport_log
- 如果傳輸層本身要記錄,那就必須這麼做,並且設定紀錄等級。:check_origin
- 如果傳輸層在存在origin
標題時,應檢查請求的來源。可能會是true
、false
、清單中允許的主機,或是以 MFA 元組提供的函式。預設值是端點設定中的:check_origin
設定。如果為
true
,標題會與YourAppWeb.Endpoint.config(:url)[:host]
中:host
進行比對。如果為
false
,且你並未在 socket 中驗證工作階段,你的應用程式會容易受到跨站式 WebSocket 劫持(CSWSH)攻擊。僅於開發階段使用,當主機真的不詳或於提供服務時,客戶端並未傳送origin
標題,例如行動應用程式。你也可以指定清單中明確允許的來源。支援萬用字元。
check_origin: [ "https://example.com", "//another.com:888", "//*.other.com" ]
或者,要接受任何與請求連線的主機、埠和架構相符的來源
check_origin: :conn
或者作為自訂 MFA 函式
check_origin: {MyAppWeb.Auth, :my_check_origin?, []}
MFA 會以請求
%URI{}
作為第一個引數進行呼叫,然後依序執行 MFA 清單中的引數,且必須回傳布林值。:code_reloader
- 啟用或停用程式碼重新載入器。預設值是你的端點設定。:connect_info
- 許多代表資料的鍵清單,會從傳輸層複製至使用者 socketconnect/3
回呼中提供。有關有效鍵,請參閱「連接資訊」小節。
連接資訊
有效鍵為
:peer_data
-Plug.Conn.get_peer_data/1
的結果:trace_context_headers
- 所有的追蹤內容標頭清單。支援的標頭由 W3C 追蹤內容規範 定義。這些標頭對於 OpenTelemetry 等函式庫,是必要的,以萃取追蹤傳遞資訊,讓你知道這個要求是一項正在進行的大型追蹤的一部分。:x_headers
- 所有以「x-」為開頭的要求標頭:uri
- 具備 conn 資訊的%URI{}
:user_agent
- 「user-agent」要求標頭的值{:session, session_config}
-Plug.Conn
的階段資訊。session_config
通常是傳送給Plug.Session
的參數之完全副本。為了驗證階段,_csrf_token
必須在將 socket 與URI.encode_www_form(Plug.CSRFProtection.get_csrf_token())
的值連接時,作為要求參數提供。CSRF 令牌要求參數可透過:csrf_token_key
選項修改。此外,
session_config
可能為 MFA,例如{MyAppWeb.Auth, :get_session_config, []}
,以允許在執行期間載入設定檔。
任意的關鍵字也可能出現在上述有效鍵的後方,這對於將自訂連線資訊傳遞給 socket 很實用。
例如
socket "/socket", AppWeb.UserSocket,
websocket: [
connect_info: [:peer_data, :trace_context_headers, :x_headers, :uri, session: [store: :cookie]]
]
使用任意的關鍵字
socket "/socket", AppWeb.UserSocket,
websocket: [
connect_info: [:uri, custom_value: "abcdef"]
]
我在哪裡能找到我的標頭 ?
出於安全考量,Phoenix 只會給你有限權限,可存取連線標頭。WebSocket 跨網域,表示當使用者「John Doe」造訪惡意的網站時,惡意的網站可以開啟與你的應用程式的 WebSocket 連線,而瀏覽器會很高興地送出 John Doe 的驗證/Cookie 資訊。假設你照單全收,惡意的網站就能完全控制與你的應用程式的 WebSocket 連線,並以 John Doe 的帳戶驗證。
為了保護你的應用程式,Phoenix 會限制並驗證 socket 可存取的連線資訊。這表示你的應用程式可免於這些攻擊,但你無法在 socket 中存取 Cookie 和其他標頭。你可以透過
:connect_info
選項,存取儲存在連線中的階段,前提是你也在透過 WebSocket 連線時傳遞了 csrf 令牌。
Websocket 設定檔
下列設定檔只適用於 :websocket
。
:timeout
- 保持 websocket 連線開放的逾時時間,自它上次收到資料後起算,預設為 60,000 毫秒:max_frame_size
- 允許的最大幀大小 (以位元組為單位),預設為「無限大」:fullsweep_after
- socket 程序強制進行一輪完整清除前的最大垃圾收集次數。你可以將它設為0
來強制更頻繁地清除你的 Websocket 傳輸程序。要設定此選項,需要 Erlang/OTP 24。:compress
- 是否針對所有資料框架啟用單一訊息壓縮,預設值為否。:subprotocols
- 一個支援的 Websocket 子協定的清單。用於握手的Sec-WebSocket-Protocol
回應標頭,預設值為 nil。例如
subprotocols: ["sip", "mqtt"]
:error_handler
- 針對連線錯誤的自訂錯誤處理器。如果Phoenix.Socket.connect/3
回傳一個{:error, reason}
叢集,錯誤處理器將會以錯誤原因呼叫。對於 WebSockets,錯誤處理器必須是一個接收到Plug.Conn
、錯誤原因的 MFA 叢集,並回傳一個帶有回應的Plug.Conn
。例如:socket "/socket", MySocket, websocket: [ error_handler: {MySocket, :handle_error, []} ]
在
MySocket
上,回傳{:error, :rate_limit}
可能是由def handle_error(conn, :rate_limit), do: Plug.Conn.send_resp(conn, 429, "Too many requests")
Longpoll組態
以下組態只適用於 :longpoll
。
:window_ms
- 使用者可以在毫秒(ms)為單位在其輪循要求中等待新訊息的長度。預設值為10_000
。:pubsub_timeout_ms
- 一個要求可以等待 pubsub 層回應的長度,以毫秒(ms)為單位。預設值為2000
。:crypto
- 由Phoenix.Token
接受,用於驗證和簽署令牌的選項。預設情況下,令牌有效期為 2 週。