Elixir Phoenix在运行时未加载环境变量
在启动phoenix服务器时,我正在尝试从mac加载一个API密钥作为系统环境。我做错了什么?以下是我的步骤:Elixir Phoenix在运行时未加载环境变量,elixir,phoenix-framework,elixir-mix,Elixir,Phoenix Framework,Elixir Mix,在启动phoenix服务器时,我正在尝试从mac加载一个API密钥作为系统环境。我做错了什么?以下是我的步骤: 在我的mac终端上: export API_NOTIFICATION_KEY=1234 在我的config.exs中 config :app, App.Notifications, notification_api_key: {:system, "API_NOTIFICATION_KEY"} 在我使用它的模块中 @api_notification_key Application
export API_NOTIFICATION_KEY=1234
config :app, App.Notifications,
notification_api_key: {:system, "API_NOTIFICATION_KEY"}
@api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]
mix phx.server
然后,当我尝试进行API调用时,它显示为nil。是否缺少使其正确加载的步骤?编译期间会对属性进行评估,因此:
@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
当我使用您的配置时,请尝试通过以下方式访问控制器中的密钥:
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
根据,您可以在endpoint.ex
中定义init/2
函数,该函数将在运行时调用——就在phoenix应用程序启动之前——这意味着您可以在运行时使用System.get_env/1
直接查找环境变量。init/2
功能的描述如下:
动态配置
用于动态配置端点,例如从
环境变量或配置文件,Phoenix调用
端点上的init/2回调,首先传递:supervisor atom
参数和端点配置作为第二个参数
我举了一个例子:
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"
@attr Application.get_env(
:app1, App1.Notifications
)[:notification_api_key]
IO.inspect(
App1Web.Endpoint.config(:notification_api_key, :not_set),
label: "config"
)
在服务器窗口中,我看到:
key: 1234
您还应该认识到,设置模块属性发生在编译时,因此此行:
@api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]
检索编译应用程序的系统的env变量
我还尝试在控制器中设置模块属性:
key = Application.get_env(
:app1, App1.Notifications
)[:notification_api_key]
IO.inspect key, label: "key"
@attr Application.get_env(
:app1, App1.Notifications
)[:notification_api_key]
IO.inspect(
App1Web.Endpoint.config(:notification_api_key, :not_set),
label: "config"
)
和上面在endpoint.ex中定义的init/2
,在我的控制器@attr中是nil——正如预期的那样。这是因为在编译时,init/2
尚未被调用,因此没有设置:notification\u api\u 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
我想我应该做点什么来配置。下面是另一个例子:
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
然后在我的控制器中:
key = Application.get_env(
:app1, App1.Notifications
)[:notification_api_key]
IO.inspect key, label: "key"
@attr Application.get_env(
:app1, App1.Notifications
)[:notification_api_key]
IO.inspect(
App1Web.Endpoint.config(:notification_api_key, :not_set),
label: "config"
)
在“我的服务器”窗口中,我看到:
config: "1234"
因此,这也是可行的。属性在编译期间进行评估——如果op在与编译应用程序的系统不同的系统上运行应用程序,这难道不会导致问题吗?换句话说,op声称env变量是在编译时之前设置的,然后应用程序被编译。因此,在编译时烘焙到应用程序中的env变量应该在运行时可用,但op得到
nil
。即使op在与编译应用程序的系统不同的系统上运行应用程序,op仍应获得1234
作为环境变量的值……。只是1234
的值不会是运行应用程序的系统上的env变量的值。嗯,我正准备写一个这样的函数,我又看了一遍你的答案。我搜索了hi和lo,以及类似这样的文章:让它看起来像凤凰有一个像你一样的本地功能。我找不到任何地方表明,当您在配置中使用系统元组时,您需要在键的值中编写自己的函数来检测:system
。我读到的所有内容都让人觉得,如果您使用系统元组,那么某些应用程序将……在运行时自动为您查找env变量。我最后得出结论,Application.get_env()
只是一个愚蠢的查找函数,它不关心是否使用:system
或其他任何东西作为键的值,而像phoenix这样的应用程序必须处理:system——如果它愿意的话。