You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Phoenix框架:如何动态配置全局路由上下文路径?

给Phoenix应用动态添加根路由前缀的解决方案

我明白你的需求啦——你想给整个Phoenix应用的API路由加上一个动态的根前缀/context,让原来的/api/test变成/context/api/test,但发现配置Endpoint的:url选项只是用来生成URL,并不会实际改变请求的匹配路径对吧?咱们可以从这两个方向来解决这个问题:

方案1:用动态作用域(Dynamic Scope)配置路由

Phoenix的路由支持直接引用配置值作为作用域前缀,这是最直接的方式。

步骤1:添加配置项

先在你的配置文件(比如config/config.exs或者对应环境的config/prod.exs)里加一个自定义配置,用来存根前缀:

config :your_app, YourAppWeb.Endpoint,
  root_context: "/context" # 你也可以从环境变量读取,比如 System.get_env("ROOT_CONTEXT") || "/context"

步骤2:修改router.ex的路由结构

在router.ex里,先从配置中读取这个前缀,再把所有路由包在这个动态作用域里:

defmodule YourAppWeb.Router do
  use YourAppWeb, :router

  # 编译时读取配置,默认空字符串避免配置缺失报错
  @root_context Application.compile_env(:your_app, YourAppWeb.Endpoint)[:root_context] || ""

  # 外层套上动态根前缀的作用域
  scope @root_context do
    scope "/api" do
      get "/test", SomeController, :test
    end
    # 其他需要加前缀的路由也可以放在这里面
  end
end

这样启动应用后,你的接口就会响应/context/api/test这个路径了。如果需要修改前缀,改完配置后重新编译应用就行。

方案2:用自定义Plug重写请求路径

如果需要运行时动态调整前缀(不用重启应用就能生效),可以写一个Plug来处理路径重写。

步骤1:创建自定义Plug

新建一个Plug文件lib/your_app_web/plugs/root_context_plug.ex:

defmodule YourAppWeb.Plugs.RootContextPlug do
  import Plug.Conn

  def init(opts), do: opts

  def call(conn, _opts) do
    # 运行时读取根前缀配置,也可以从其他地方获取
    root_context = Application.get_env(:your_app, YourAppWeb.Endpoint)[:root_context] || ""

    if root_context != "" and String.starts_with?(conn.request_path, root_context) do
      # 去掉前缀,让后续路由能匹配到原来的/api/test路径
      new_path = String.replace_prefix(conn.request_path, root_context, "")
      # 更新conn的请求路径和路径信息
      %{conn | request_path: new_path, path_info: split_path(new_path)}
    else
      conn
    end
  end

  # 辅助函数:把路径拆成Phoenix需要的path_info格式
  defp split_path(path) do
    path |> String.trim("/") |> String.split("/") |> Enum.reject(&(&1 == ""))
  end
end

步骤2:把Plug加到Endpoint里

在endpoint.ex中,把这个Plug放在Router之前:

defmodule YourAppWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :your_app

  # ... 其他已有的Plug配置(比如Parsers、Session等)

  # 加在Router之前,先处理路径重写
  plug YourAppWeb.Plugs.RootContextPlug
  plug YourAppWeb.Router
end

这种方式下,你可以随时通过Application.put_env(:your_app, YourAppWeb.Endpoint, root_context: "/new_context")来修改前缀,不需要重启应用就能生效。

额外注意点

不管用哪种方案,如果你需要在代码里生成正确的URL(比如控制器里用Routes.test_path(conn, :test)),记得同步配置Endpoint的:url选项里的:path参数,这样生成的URL才会带上前缀:

config :your_app, YourAppWeb.Endpoint,
  url: [host: "your-domain.com", path: "/context"],
  root_context: "/context"

内容的提问来源于stack exchange,提问作者Oliver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:57:20