Как выбрать Config на основе серверной переменной во Flask?
Я бегу nginx + gunicorn + колбу
Мой конфиг nginx выглядит так:
...
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Stage "development";
proxy_redirect off;
...
Мое приложение для колб выглядит так:
from flask import Flask, request
from werkzeug.contrib.fixers import ProxyFix
app = Flask(__name__)
# configuration settings
if request.headers.get('Stage') == 'production':
app.config.from_object('config.production_config')
else:
app.config.from_object('config.development_config')
@app.route('/')
def index():
return "hello"
app.wsgi_app = ProxyFix(app.wsgi_app)
Тем не мение,
Это не похоже на работу.
Я получаю: RuntimeError: работает вне контекста запроса
Мой nginx настроен так, чтобы у меня была среда разработки / производства, но я хочу сказать, что это "расположение сервера" является средой разработки, и я хочу, чтобы Flask использовал соответствующую конфигурацию.
2 ответа
Конфигурация приложения предназначена для всего приложения, а заголовки запросов - только для одного запроса. Одно и то же приложение обычно обрабатывает много запросов. Поэтому вы не можете установить конфигурацию на основе заголовков запросов.
Ваш код на уровне модуля выполняется при запуске сервера, когда еще не поступило ни одного запроса, поскольку приложение еще не поступило. Это то, что означает сообщение "работа вне контекста запроса".
То, что вы пытаетесь сделать (prod vs. dev config), лучше всего сделать с помощью переменной окружения в скрипте, запускающем ваш сервер gunicorn. Если вы хотите использовать оба одновременно, проще всего запустить два сервера gunicorn.
В качестве альтернативы создайте два объекта приложения, запустите их оба в одном и том же процессе и отправьте с промежуточным программным обеспечением WSGI, похожим на следующее: http://flask.pocoo.org/docs/patterns/appdispatch/
Это немного устарело, но я хотел бы добавить, как мы делаем это с помощью колбы. Большая часть этого адаптирована с http://flask.pocoo.org/docs/config/.
В нашем config.py мы определяем несколько классов (по одному на среду):
class Config(object):
FOO = 1
BAR = 2
class Development(Config):
BAR = 3
Затем в каждом из наших узлов приложения мы устанавливаем переменную окружения в сценариях инициализации gunicorn (для нас это живет в конфигурации супервизора, но это не обязательно).
APPLICATION_ENV='Development'
Затем в приложении-колбе во время инициализации (запускается только при запуске сервера, а не в контексте запроса):
try:
env = os.environ['APPLICATION_ENV']
except KeyError as e:
logging.error('Unknown environment key, defaulting to Development')
env = 'Development'
app.config.from_object('config.%s' % env)
теперь app.config['BAR'] будет 3.
Мы также хотели поддерживать локальные конфигурационные файлы (например, на компьютере разработчика или пароли, которые развертываются непосредственно от chef на машине и не хранятся в git). Для этого мы расширили вышеприведенное, чтобы также загрузить локальную конфигурацию на основе параметра app.config['LOCAL_CONFIG'].
class Development(Config):
BAR = 3
LOCAL_CONFIG = '/etc/localConfig.py'
А затем в /etc/localConfig.py
BAR = 4
И снова в нашем коде инициализации приложения после кода выше загружается исходный app.config для среды:
if 'LOCAL_CONFIG' in app.config:
#try to load the local configuration overrides
if app.config.from_pyfile(app.config['LOCAL_CONFIG'], silent=True):
logging.info('Loaded local config file at %s' % app.config['LOCAL_CONFIG'])
else:
logging.warning('Failed to load local config file at %s - does it exist?' % app.config['LOCAL_CONFIG'])
На данный момент app.config['BAR'] равно 4.
Это не идеально, потому что если в вашей конфигурации есть dict, вы сможете переопределить только весь dict, а не ключи внутри него. Это действительно выполняет большую часть того, что нам нужно.