【问题标题】:Elixir/Phoenix: How to use third-party modules in config files?Elixir/Phoenix:如何在配置文件中使用第三方模块?
【发布时间】:2018-03-16 20:40:46
【问题描述】:

config.exsdev.exs/prod.exs/test.exs中使用第三方模块时,似乎phoenix中配置文件的加载和编译方式存在问题。

示例:要设置 Guardian 进行 JWT 身份验证,我正在尝试使用 JOSE.JWK 模块在我的 config.exs 中创建/加载 JWK。我可以通过iex -S mix phoenix.server 在控制台中使用该模块。它当然是作为依赖安装的。我得到的错误是

** (Mix.Config.LoadError) could not load config config/config.exs
    ** (UndefinedFunctionError) undefined function JOSE.JWK.from_file/2 (module JOSE.JWK is not available)

这是我的 config.exs 中的代码

# Configure Guardian for JWT Authentication
config :guardian, Guardian,
  allowed_algos: ["HS512"], # optional
  verify_module: Guardian.JWT,  # optional
  issuer: "MyApp",
  ttl: { 30, :days },
  verify_issuer: true, # optional
  secret_key: System.get_env("GUARDIAN_KEY_PASSPHRASE") |> JOSE.JWK.from_file(System.get_env("GUARDIAN_KEY_FILE")),
  serializer: MyApp.GuardianSerializer

当我将对JOSE.JWK.from_file/2 的调用包装在匿名函数中时,它可以工作。但是当然 Guardian.config(:secret_key) 的值是匿名函数本身,而不是它的返回值:

# Configure Guardian for JWT Authentication
config :guardian, Guardian,
  allowed_algos: ["HS512"], # optional
  verify_module: Guardian.JWT,  # optional
  issuer: "MyApp",
  ttl: { 30, :days },
  verify_issuer: true, # optional
  secret_key: fn -> System.get_env("GUARDIAN_KEY_PASSPHRASE") |> JOSE.JWK.from_file(System.get_env("GUARDIAN_KEY_FILE")) end,
  serializer: MyApp.GuardianSerializer

在这个例子中这没问题,因为 Guardian 接受了一个用于这个配置值的函数。但我可以想象这可能成为问题的其他情况。

这个限制是故意的吗?我错过了什么吗?有没有办法解决这个问题?

【问题讨论】:

  • 我现在要解决的解决方法是:将Code.load_file("config/support.exs") 放在config/config.exs 的顶部,然后将带有辅助函数的.exs 代码放在那里。我知道这不是一个令人满意的答案,但似乎没有。

标签: elixir phoenix-framework


【解决方案1】:

由于在编译依赖项之前对配置进行了评估,因此您不能在配置中使用依赖项中的代码。

原因很简单:配置可能会改变依赖项的编译方式。您需要决定首先要做什么 - 编译以评估配置。已决定首先评估配置,因为通过配置操作编译比使用依赖项配置其他应用程序更有用(也更频繁)——最常见的配置只是原始数据。

【讨论】:

  • 同样的问题适用于从应用程序本身访问函数,而不是依赖项。这导致github.com/trenpixster/addict/issues/105 的痛苦
  • 你确定吗? config :my_app, MyApp.Endpoint, 是如何工作的?
  • @asiniy MyApp.Endpoint 只是一个原子。如果是MyApp.Endpoint.foo(),那就是函数调用,需要编译依赖模块。
【解决方案2】:

如果您在运行 mix 之前首先编译位于 elixirc_paths 之外的模块并且它位于 elixir 搜索路径中,它会找到它。就做Whatever.foo(:bar)

将预编译打包为一个混合任务会更有意义,并在调用第 3 方dep 之前调用 mix 以确保配置 dep 是最新的。

如果有一个预配置混合钩子和/或在评估配置之前预编译的config/lib,将会很有帮助。否则,即使使用import_config 不会让您模块化和干燥代码,配置也会增长并变成令人作呕的代码堆。

另一个 hackaround 是有一个最小的混合任务,它加载你的应用程序的足够多的值来获取值并将它们写入标准输出,然后使用端口在需要的地方获取它们(Rails 在某些地方执行此操作)。

【讨论】:

  • 许多构建系统实际上都有构建与运行时依赖关系的概念。这也可能是添加到 Mix 中的合理区别。它恰好在编译语言时使用。 Java 和 Javascript - 以现在的方式编译 - 浮现在脑海中。
【解决方案3】:

事实证明,使用档案可以通过 Mix 做到这一点。

它们需要手动安装,但可以使用单独的 Mix 项目和 mix archive.build 轻松构建。

它们的局限性在于存档项目不能拥有自己的依赖项。

有关详细信息,请参阅文档。 https://hexdocs.pm/mix/Mix.Tasks.Archive.Build.html#content

【讨论】:

    猜你喜欢
    • 2016-06-14
    • 2016-05-21
    • 2022-12-04
    • 2020-04-26
    • 2018-02-19
    • 2020-09-04
    • 2018-05-30
    • 2017-12-16
    • 1970-01-01
    相关资源
    最近更新 更多