来自env var、使用load_dotenv加载并使用os.environ.get获取的Flask config变量有时为None

2024-05-15 18:04:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在经历一种我无法弄清的最奇怪的行为,它让我发疯

我使用make目标在本地启动flask应用程序。它运行的命令如下:

export FLASK_APP=foodbank_southlondon.launch:main FBSL_ENVIRONMENT=dev FLASK_ENV=development && \
    . $(_VENV_ACTIVATE) && \
    flask run

以下是launch.py的内容:

import logging
import os

import dotenv

from foodbank_southlondon import api, app, bff, config, oauth
from foodbank_southlondon.api import events, lists, requests
import foodbank_southlondon.views  # noqa: F401
import foodbank_southlondon.errors  # noqa: F401
import foodbank_southlondon.api.errors  # noqa: F401
import foodbank_southlondon.api.events.views  # noqa: F401
import foodbank_southlondon.api.lists.views  # noqa: F401
import foodbank_southlondon.api.requests.views  # noqa: F401
import foodbank_southlondon.bff.views  # noqa: F401


# ENVIRONMENT VARIABLES
_FBSL_ENVIRONMENT_ENV_VAR = "FBSL_ENVIRONMENT"


def main():
    environment = os.environ.get(_FBSL_ENVIRONMENT_ENV_VAR)
    app.logger.setLevel(logging.INFO if environment == "prod" else logging.DEBUG)
    env_file_path = os.path.join(app.root_path, "..", f"{environment}.env")
    app.logger.info(f"Loading .env file, {env_file_path}...")
    dotenv.load_dotenv(env_file_path)
    app.logger.info(f"Loading environment, {environment} ...")
    app.config.from_object(config.CONFIGURATIONS[environment])
    app.logger.info(f"Initialising APIs, OAuth, attaching namespaces and registering blueprints  ...")
    oauth.register(name="google", server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
                   client_kwargs={"scope": "openid email profile"})
    oauth.init_app(app)
    api.rest.init_app(api.blueprint)
    api.rest.add_namespace(events.namespace)
    api.rest.add_namespace(lists.namespace)
    api.rest.add_namespace(requests.namespace)
    app.register_blueprint(api.blueprint, url_prefix="/api")
    bff.rest.init_app(bff.blueprint)
    app.register_blueprint(bff.blueprint, url_prefix="/bff")
    return app

下面是config.py的精简内容,需要注意的重要一点是,我的dev config类继承自基类,基类是唯一定义GOOGLE\u CLIENT\u SECRET的地方,它来自os.environ.get:

import os


class _Config(object):
    ...
    GOOGLE_CLIENT_SECRET = os.environ.get("FBSL_CLIENT_SECRET")
    ...


class DevelopmentConfig(_Config):
    ... # i don't set GOOGLE_CLIENT_SECRET here


class ProductionConfig(_Config):
    ...

CONFIGURATIONS = {
    "dev": DevelopmentConfig,
    "prod": ProductionConfig
}

dev.env内:

FBSL_CLIENT_SECRET = secret
FBSL_SA_KEY = secret

附加上下文

我的后端将react SPA作为一组静态文件提供服务。当用户点击我的网站时,例如localhost:5000/my flask route会立即将他们重定向到Google登录(使用authlib)。谷歌将它们发送回我的/auth回调,如果他们有权限访问我的站点,我会将它们重定向回/但这次我为他们提供静态文件,而不是重定向到登录。Authlib需要将app config变量GOOGLE_CLIENT_SECRET设置为能够通过Google对其进行授权

问题

第一次启动服务器时,服务器启动得很好,我看到日志消息显示正在执行dev.env。当调试模式打开时,会出现典型的双输出:

export FLASK_APP=foodbank_southlondon.launch:main FBSL_ENVIRONMENT=dev FLASK_ENV=development && \
. .venv/bin/activate && \
flask run
 * Serving Flask app "foodbank_southlondon.launch:main" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 277-037-026
[2020-05-08 09:21:50,778] INFO in launch: Loading .env file, /home/ac/Projects/Home/foodbank-southlondon/backend/foodbank_southlondon/../dev.env...
[2020-05-08 09:21:50,779] INFO in launch: Loading environment, dev ...
[2020-05-08 09:21:50,779] INFO in launch: Initialising APIs, OAuth, attaching namespaces and registering blueprints  ...
[2020-05-08 09:21:50,919] INFO in launch: Loading .env file, /home/ac/Projects/Home/foodbank-southlondon/backend/foodbank_southlondon/../dev.env...
[2020-05-08 09:21:50,919] INFO in launch: Loading environment, dev ...
[2020-05-08 09:21:50,920] INFO in launch: Initialising APIs, OAuth, attaching namespaces and registering blueprints  ...

我可以访问localhost:5000,然后我被重定向到登录,我登录了,我看到了网站

如果我停止我的Web服务器,然后以完全相同的方式重新启动它,我会看到完全相同的终端输出。如果随后访问localhost:5000,我会在调试器中看到此错误及其回溯:

authlib.integrations.base_client.errors.OAuthError
authlib.integrations.base_client.errors.OAuthError: invalid_request: client_secret is missing.

如果单击调试器并打开交互式shell并键入:

from foodbank_southlondon import app
print(app.config)

我看到了所有的配置变量,所有的设置都如预期的那样,除了我使用os.environ.get加载的2个配置变量之外,它们都没有

为了解决这个疯狂的问题,我必须对config.py进行一些修改。例如,如果我将print(GOOGLE_CLIENT_SECRET)写在定义它的正下方,我不仅会看到这个不是None值的输出,而且我引入print语句的行为也会修复它!但是如果我停止服务器并再次启动它,我会再次遇到同样的问题,我需要以某种方式更改文件

最后一点:如果我不停止服务器,让重新加载程序重新加载,我可以避免这个问题

我假设我不会在生产中遇到这个问题,但这会让开发变得非常痛苦,这只是一个疯狂的问题。这就好像我在停止和启动服务器之间遇到了某种奇怪的环境变量缓存问题。我不知道。请帮忙


Tags: devimportinfoenvapiconfigappenvironment
1条回答
网友
1楼 · 发布于 2024-05-15 18:04:58

唉,这跟执行命令有关。。。在环境变量设置之前导入配置模块,因此os.ENVIRO.get评估为无。我已经将使用os.environ.get的类变量放入实例属性(@property)中,并在我的config dict中实例化该类来解决这个问题

相关问题 更多 >