查看源代码 Phoenix.Endpoint 行为 (Phoenix v1.7.14)

定义一个 Phoenix 端点。

端点是所有对您的 Web 应用程序请求的起始边界。它也是您的应用程序提供给底层 Web 服务器的接口。

总的来说,端点有三个职责

  • 作为监督树的一部分,为启动和停止端点提供包装器

  • 为请求通过的初始插座管道定义

  • 为您的应用程序托管 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.exsconfig/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),它会使用 :url 配置中指定的 :host 重定向到 HTTPS 版本。要动态重定向到当前请求的 host,请在 :force_ssl 配置中将 :host 设置为 nil

运行时配置

以下配置可以在 config/dev.exsconfig/prod.exs 等上设置,也可以在 config/runtime.exs 上设置。通常,如果您需要使用系统环境变量配置它们,您将在 config/runtime.exs 中设置它们。这些选项也可以在您的监督树中启动端点时设置,例如 {MyApp.Endpoint, options}

  • :adapter - 用于服务 Web 请求的 Web 服务器适配器。请参见下面的“适配器配置”部分

  • :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 时,在端点监督树启动时启动 Web 服务器。默认为 falsemix phx.server 任务会自动将其设置为 true

  • :url - 用于在整个应用程序中生成 URL 的配置。接受 :host:scheme:path:port 选项。除 :path 之外的所有键都可以在运行时更改。默认为

    [host: "localhost", path: "/"]

    :port 选项需要整数或字符串。 :host 选项需要字符串。

    :scheme 选项接受 "http""https" 值。默认值从顶层 :http:https 选项推断。当将 Phoenix 托管在负载均衡器或反向代理后面并在那里终止 SSL 时,它很有用。

    :path 选项可用于覆盖根路径。在使用 URL 重写规则将 Phoenix 托管在反向代理后面时很有用

  • :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://localhost: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 - 在通道和通过端点广播功能中使用的 PubSub 服务器的名称。PubSub 服务器通常在您的监督树中启动。

  • :render_errors - 负责在应用程序出现故障时呈现模板。例如,如果应用程序在 HTML 请求期间因 500 错误而崩溃,则会调用 render("500.html", assigns) 在传递给 :render_errors 的视图中。可以提供 :formats 列表以指定每个格式的模块来处理错误呈现。例子

    [formats: [html: MyApp.ErrorHTML], layout: false, log: :debug]
  • :log_access_url - 在服务器启动后记录访问 URL

请注意,您也可以将自己的配置存储在 Phoenix.Endpoint 中。例如,Phoenix LiveView 期望在 :live_view 键下有自己的配置。在这种情况下,您应该查阅相应项目的文档。

适配器配置

Phoenix 允许您选择要使用的 Web 服务器适配器。通过 phx.new Mix 任务创建的新生成应用程序使用 Bandit Web 服务器,通过 Bandit.PhoenixAdapter 适配器。如果没有通过 adapter 选项指定,Phoenix 将回退到 Phoenix.Endpoint.Cowboy2Adapter 以向后兼容在 Phoenix 1.7.8 之前生成的应用程序。

两种适配器都可以使用以下两个顶级选项以类似的方式配置

  • :http - HTTP 服务器的配置。它接受所有选项,如 BanditPlug.Cowboy 定义的那样,具体取决于您的适配器选择。默认为 false

  • :https - HTTPS 服务器的配置。它接受所有选项,如 BanditPlug.Cowboy 定义的那样,具体取决于您的适配器选择。默认为 false

此外,连接排水可以通过以下顶级选项为 Cowboy Web 服务器配置(这对于 Bandit 来说不是必需的,因为它内置了连接排水)

  • :drainer - 一个 drainer 进程在应用程序关闭时等待任何正在进行的请求完成。它接受由 Plug.Cowboy.Drainer 定义的 :shutdown:check_interval 选项。注意,排空不会终止任何现有连接,它只是等待它们完成。套接字连接在调用此排空程序之前运行自己的排空程序。这是因为套接字是有状态的,可以优雅地通知,这使我们能够在更长的时间内交错它们。有关更多信息,请参阅 socket/3 的文档。

端点 API

在上一节中,我们使用了在您的端点中自动生成的 config/2 函数。以下是您的端点中自动定义的所有函数的列表。

摘要

回调

msg 作为 event 在给定的 topic 中广播到所有节点。

msg 作为 event 在给定的 topic 中广播到所有节点。

从给定的 frommsg 广播为给定 topic 中的 event,广播到所有节点。

从给定的 frommsg 广播为给定 topic 中的 event,广播到所有节点。

访问由 key 给出的端点配置。

在应用程序升级时重新加载端点配置。

从 :url 配置中返回主机。

msg 作为 event 在给定的 topic 中广播到当前节点。

从给定的 frommsg 广播为给定 topic 中的 event,广播到当前节点。

在路由到此端点时生成路径信息。

从 :url 配置中返回脚本名称。

返回服务器运行的地址和端口。

启动端点监督树。

生成对 priv/static 中静态文件的完整性哈希。

生成一个包含 static_pathstatic_integrity 的两个元素元组。

生成对 priv/static 中静态文件的路由。

生成不包含任何路径信息的静态 URL。

生成端点基本 URL,但作为 URI 结构。

将调用者订阅到给定的主题。

将调用者从给定的主题中取消订阅。

生成不包含任何路径信息的端点基本 URL。

函数

检查端点的 Web 服务器是否已配置为启动。

socket 定义一个 websocket/longpoll 挂载点。

类型

@type event() :: String.t()
@type msg() :: map() | {:binary, binary()}
@type topic() :: String.t()

回调

链接到此回调

broadcast(topic, event, msg)

查看源代码
@callback broadcast(topic(), event(), msg()) :: :ok | {:error, term()}

msg 作为 event 在给定的 topic 中广播到所有节点。

链接到此回调

broadcast!(topic, event, msg)

查看源代码
@callback broadcast!(topic(), event(), msg()) :: :ok

msg 作为 event 在给定的 topic 中广播到所有节点。

如果失败,则引发异常。

链接到此回调

broadcast_from(from, topic, event, msg)

查看源代码
@callback broadcast_from(from :: pid(), topic(), event(), msg()) :: :ok | {:error, term()}

从给定的 frommsg 广播为给定 topic 中的 event,广播到所有节点。

链接到此回调

broadcast_from!(from, topic, event, msg)

查看源代码
@callback broadcast_from!(from :: pid(), topic(), event(), msg()) :: :ok

从给定的 frommsg 广播为给定 topic 中的 event,广播到所有节点。

如果失败,则引发异常。

@callback config(key :: atom(), default :: term()) :: term()

访问由 key 给出的端点配置。

链接到此回调

config_change(changed, removed)

查看源代码
@callback config_change(changed :: term(), removed :: term()) :: term()

在应用程序升级时重新加载端点配置。

@callback host() :: String.t()

从 :url 配置中返回主机。

链接到此回调

local_broadcast(topic, event, msg)

查看源代码
@callback local_broadcast(topic(), event(), msg()) :: :ok

msg 作为 event 在给定的 topic 中广播到当前节点。

链接到此回调

local_broadcast_from(from, topic, event, msg)

查看源代码
@callback local_broadcast_from(from :: pid(), topic(), event(), msg()) :: :ok

从给定的 frommsg 广播为给定 topic 中的 event,广播到当前节点。

@callback path(path :: String.t()) :: String.t()

在路由到此端点时生成路径信息。

@callback script_name() :: [String.t()]

从 :url 配置中返回脚本名称。

@callback server_info(Plug.Conn.scheme()) ::
  {:ok,
   {:inet.ip_address(), :inet.port_number()} | :inet.returned_non_ip_address()}
  | {:error, term()}

返回服务器运行的地址和端口。

@callback start_link(keyword()) :: Supervisor.on_start()

启动端点监督树。

启动端点的配置缓存,并可能启动用于处理请求的服务器。

链接到此回调

static_integrity(path)

查看源代码
@callback static_integrity(path :: String.t()) :: String.t() | nil

生成对 priv/static 中静态文件的完整性哈希。

@callback static_lookup(path :: String.t()) ::
  {String.t(), String.t()} | {String.t(), nil}

生成一个包含 static_pathstatic_integrity 的两个元素元组。

@callback static_path(path :: String.t()) :: String.t()

生成对 priv/static 中静态文件的路由。

@callback static_url() :: String.t()

生成不包含任何路径信息的静态 URL。

@callback struct_url() :: URI.t()

生成端点基本 URL,但作为 URI 结构。

链接到此回调

subscribe(topic, opts)

查看源代码
@callback subscribe(topic(), opts :: Keyword.t()) :: :ok | {:error, term()}

将调用者订阅到给定的主题。

有关选项,请参阅 Phoenix.PubSub.subscribe/3

@callback unsubscribe(topic()) :: :ok | {:error, term()}

将调用者从给定的主题中取消订阅。

@callback url() :: String.t()

生成不包含任何路径信息的端点基本 URL。

函数

链接到此函数

server?(otp_app, endpoint)

查看源代码

检查端点的 Web 服务器是否已配置为启动。

  • otp_app - 运行端点的 OTP 应用程序,例如 :my_app
  • endpoint - 端点模块,例如 MyAppWeb.Endpoint

示例

iex> Phoenix.Endpoint.server?(:my_app, MyAppWeb.Endpoint)
true
链接到此宏

socket(path, module, opts \\ [])

查看源代码 (宏)

socket 定义一个 websocket/longpoll 挂载点。

它需要一个 path、一个 socket 模块和一组选项。套接字模块通常使用 Phoenix.Socket 定义。

Websocket 和长轮询连接都开箱即用地支持。

选项

  • :websocket - 控制 websocket 配置。默认值为 true。可以是 false 或选项的关键字列表。有关整个列表,请参阅 "通用配置""WebSocket 配置"

  • :longpoll - 控制长轮询配置。默认值为 false。可以是 true 或选项的关键字列表。有关整个列表,请参阅 "通用配置""长轮询配置"

  • :drainer - 一个关键字列表或一个返回关键字列表的自定义 MFA 函数,例如

    {MyAppWeb.Socket, :drainer_configuration, []}

    配置如何在应用程序关闭时排空套接字。目标是通知所有频道(和 LiveView)客户端重新连接。支持的选项是

    • :batch_size - 在给定批次中一次通知多少个客户端。默认值为 10000。
    • :batch_interval - 批次终止的给定时间(以毫秒为单位)。默认值为 2000 毫秒。
    • :shutdown - 允许排空所有批次的总时间(以毫秒为单位)。默认值为 30000 毫秒。

    例如,如果您有 150k 个连接,则默认值会将它们分成 15 个批次,每个批次 10k 个连接。每个批次在下一个批次开始之前需要 2000 毫秒。在这种情况下,我们将在最大关闭时间 30000 毫秒内完成所有操作。因此,随着连接数的增加,请记住相应地调整关闭时间。最后,在套接字排空程序运行后,更低级别的 HTTP/HTTPS 连接排空程序将继续运行,并应用于所有连接。将其设置为 false 以禁用排空。

您也可以在 use Phoenix.Socket 上传递以下选项。这里指定的 value 会覆盖 use Phoenix.Socket 中的 value。

示例

socket "/ws", MyApp.UserSocket

socket "/ws/admin", MyApp.AdminUserSocket,
  longpoll: true,
  websocket: [compress: true]

路径参数

可以在路径中包含变量,这些变量将在传递给套接字的 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 标头时应该检查请求的来源。可以是 truefalse、允许的主机列表或作为 MFA 元组提供的函数。默认值为端点配置中的 :check_origin 设置。

    如果为 true,则会根据 YourAppWeb.Endpoint.config(:url)[:host] 中的 :host 检查标头。

    如果为 false 并且您没有在套接字中验证会话,那么您的应用程序会容易受到跨站点 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 - 一个表示从传输层复制到 user socket connect/3 回调中可用的数据的键列表。有关有效键,请参阅“连接信息”小节。

连接信息

有效键是

  • :peer_data - Plug.Conn.get_peer_data/1 的结果。

  • :trace_context_headers - 所有跟踪上下文标头的列表。支持的标头由 W3C 跟踪上下文规范 定义。这些标头对于 OpenTelemetry 等库来说是必要的,以便提取跟踪传播信息,从而知道此请求是正在进行的更大跟踪的一部分。

  • :x_headers - 所有以“x-”开头的请求标头。

  • :uri - 一个包含来自连接的信息的 %URI{}

  • :user_agent - “user-agent” 请求标头的 value。

  • {:session, session_config} - 来自 Plug.Conn 的会话信息。session_config 通常是传递给 Plug.Session 的参数的完全副本。为了验证会话,在使用 URI.encode_www_form(Plug.CSRFProtection.get_csrf_token()) 的 value 连接套接字时,"_csrf_token" 必须作为请求参数提供。CSRF 令牌请求参数可以通过 :csrf_token_key 选项修改。

    此外,session_config 可以是一个 MFA,例如 {MyAppWeb.Auth, :get_session_config, []},以便在运行时加载配置。

在上述有效键之后还可以出现任意关键字,这对于将自定义连接信息传递到套接字很有用。

例如

  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 限制并验证套接字可以访问的连接信息。这意味着您的应用程序可以免受这些攻击,但您无法在套接字中访问 Cookie 和其他头文件。您可以通过 :connect_info 选项访问存储在连接中的会话,前提是在通过 WebSocket 连接时也传递 csrf 令牌。

WebSocket 配置

以下配置仅适用于 :websocket

  • :timeout - 在最后一次接收数据后保持 WebSocket 连接打开的超时时间,默认为 60_000 毫秒

  • :max_frame_size - 允许的最大帧大小(以字节为单位),默认为“无穷大”

  • :fullsweep_after - 在强制对套接字进程进行完全清除之前,垃圾收集的最大次数。您可以将其设置为 0 以强制更频繁地清理您的 WebSocket 传输进程。设置此选项需要 Erlang/OTP 24

  • :compress - 是否在所有数据帧上启用每消息压缩,默认为 false

  • :subprotocols - 支持的 WebSocket 子协议列表。用于握手 Sec-WebSocket-Protocol 响应头,默认为 nil。

    例如

    subprotocols: ["sip", "mqtt"]
  • :error_handler - 连接错误的自定义错误处理程序。如果 Phoenix.Socket.connect/3 返回一个 {:error, reason} 元组,则错误处理程序将使用错误原因调用。对于 WebSocket,错误处理程序必须是一个接收 Plug.Conn、错误原因并返回带有响应的 Plug.Conn 的 MFA 元组。例如

    socket "/socket", MySocket,
        websocket: [
          error_handler: {MySocket, :handle_error, []}
        ]

    并且 {:error, :rate_limit} 返回可能在 MySocket 上处理为

    def handle_error(conn, :rate_limit), do: Plug.Conn.send_resp(conn, 429, "Too many requests")

长轮询配置

以下配置仅适用于 :longpoll

  • :window_ms - 客户端在轮询请求中等待新消息的最长时间(以毫秒 (ms) 为单位)。默认为 10_000

  • :pubsub_timeout_ms - 请求等待 PubSub 层响应的最长时间(以毫秒 (ms) 为单位)。默认为 2000

  • :crypto - 用于验证和签署令牌的选项,由 Phoenix.Token 接受。默认情况下,令牌有效期为 2 周