Elixir Phoenix在运行时未加载环境变量

时间:2019-06-27 01:29:30

标签: elixir phoenix-framework mix

启动phoenix服务器时,我试图从Mac上将API密钥作为系统环境加载。我怎么了?这些是我的步骤:

  1. 在我的Mac终端上:

    export API_NOTIFICATION_KEY=1234
    
  2. 在我的config.exs中

    config :app, App.Notifications,
    notification_api_key: {:system, "API_NOTIFICATION_KEY"}
    
  3. 在我使用它的模块中

    @api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]
    
  4. 启动我的凤凰服务器

    mix phx.server
    

然后当我尝试进行API调用时,它显示为nil。我缺少要正确加载的步骤吗?

2 个答案:

答案 0 :(得分:2)

在编译过程中评估属性,因此:

@api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]

将在编译时设置其值。我认为那不是您想要的,所以使用一个函数会更好:

defp api_notification_key() do
  case Application.get_env(:test, App.Notifications)[:notification_api_key] do
    {:system, var_name} -> System.get_env(var_name)
    value -> value
  end
end

答案 1 :(得分:0)

当我使用您的配置时,然后尝试使用以下命令访问控制器中的密钥:

Application.get_env(:app, App.Notifications)[:notification_api_key]

我得到:

{:system, "API_NOTIFICATION_KEY"}

因此phoenix没有查找env变量。另一方面,如果我在配置中手动设置密钥,如下所示:

config :app, App.Notifications,
    notification_api_key: 1234

然后我在控制器中得到1234。我读到一些东西说用{:system, "ENV_VAR"}读取环境变量将在某个时候被弃用,并且我在文档中没有看到关于:system的任何提及。我正在使用phoenix 1.4.6

根据this article,您可以在init/2中定义一个endpoint.ex函数,该函数将在运行时(在您的phoenix应用程序启动之前)被调用,这意味着您可以直接在运行时使用System.get_env/1查找环境变量。 Phoenix.Endpoint docs中描述了init/2函数:

  

动态配置

     

用于动态配置端点,例如从   环境变量或配置文件,Phoenix调用   端点上的init / 2回调,首先传递:supervisor原子   参数,端点配置为第二。

这是我想出的一个例子:

  def init(:supervisor, config) do
    #IO.inspect config, label: "config"
    #IO.inspect Application.get_all_env(:app1), label: "all"

    Application.put_env(:app1, :notification_api_key, 
        System.get_env("API_NOTIFICATION_KEY"),
        persistent: true
    )

    {:ok, config}
  end

然后在我的控制器中

key = Application.get_env(
        :app1, App1.Notifications 
      )[:notification_api_key]

IO.inspect key, label: "key" 

然后,在服务器窗口中,我看到:

key: 1234

您还应该认识到设置模块属性是在编译时发生的,所以这一行:

@api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]

检索在其上编译应用程序的系统的env变量。

我还尝试在控制器中设置模块属性:

@attr Application.get_env(
        :app1, App1.Notifications 
      )[:notification_api_key]
如上在endpoint.ex中定义的

init/2,以及在我的控制器中的@attr为nil-符合预期。这是因为在编译时尚未调用init/2,因此尚未设置:notification_api_key的值。

对我来说,在Application.put_env()中调用init/2感觉不对:

  def init(:supervisor, config) do

    Application.put_env(:app1, :notification_api_key, 
        System.get_env("API_NOTIFICATION_KEY"),
        persistent: true
    )

    {:ok, config}
  end

我认为我应该对config做些事情。这是另一个示例:

  def init(:supervisor, config) do

    IO.inspect config, label: "config"

    key = System.get_env("API_NOTIFICATION_KEY")
    new_config = Keyword.put_new(config, :notification_api_key, key)

    IO.inspect new_config, label: "inside init/2: new_config"

    {:ok, new_config}
  end

然后在我的控制器中

IO.inspect(
  App1Web.Endpoint.config(:notification_api_key, :not_set), 
  label: "config"
)

在服务器窗口中,我看到:

config: "1234"

所以也可以。