Python 我如何在Flask/WSGI服务器中使用应用程序工厂,为什么它可能不安全? 关于应用程序可调用、WSGI服务器和Flask循环导入的问题
我(可能)糊涂了。我想安全地创建Flask/WSGI应用程序 并且仍然能够在WSGI服务器中轻松使用它们 tl;博士Python 我如何在Flask/WSGI服务器中使用应用程序工厂,为什么它可能不安全? 关于应用程序可调用、WSGI服务器和Flask循环导入的问题,python,flask,wsgi,Python,Flask,Wsgi,我(可能)糊涂了。我想安全地创建Flask/WSGI应用程序 并且仍然能够在WSGI服务器中轻松使用它们 tl;博士 我可以安全地避免在导入init时创建应用程序吗 建议)以后再创建(即使用工厂方法) 如何使该应用程序与WSGI服务器配合使用?尤其地 当我传入配置和其他设置时,不拉它们 来自ENV 例如: def make_app(configdict, appname): app = Flask(appname) app.config.update(configdict)
def make_app(configdict, appname):
app = Flask(appname)
app.config.update(configdict)
init_db(configdict)
set_app_in_global_namespace(app)
#importing now will allow from pkg import app
from mypackage import views
return app
我想使用上面的“工厂”,因为我想轻松地控制测试等的配置
然后我大概想创建一个wsgi.py模块,将应用程序提供给wsgi服务器
所以最终事情看起来有点像这样
init.py::
app = None
def make_app(configdict, appname):
flaskapp = Flask(appname)
flaskapp.config.update(configdict)
init_db(configdict)
global app
app = flaskapp
#importing now will allow from pkg import app
from mypackage import views
return flaskapp
py::
from mypackage import app
app = make_app(configfromsomewhere, "myname")
uWSGI::
uwsgi --module=mypackage.wsgi:app
但是wsgi.py仍然不是像wsgi.py--settings=x--host=10.0.0.1那样我可以调用的东西
所以我真的不知道如何传递配置
我这么问是因为虽然这看起来。。。好啊也有点乱
当一切都在环境中时,生活就容易多了
不仅如此,而且:
那么,使用应用程序工厂有什么不安全之处呢
此处给出的建议
_
是::
回复:2,很明显,路线装饰者期望从
实例化的应用程序,没有它们无法运行。那很好
回复:1.,好的,我们需要正确的名称。但什么是不安全的?及
为什么?如果未初始化,则导入和使用应用程序是否不安全?
嗯,它会断裂,但这并不不安全。
这是被吹嘘的本地线程吗?可能地但如果我在拔
应用程序实例故意从随机模块中删除,我认为会有麻烦
含义-我们不从视图以外的任何地方引用应用程序对象-本质上,我们保持模块化良好且紧凑,并进行传递
dicts、错误对象,甚至WebObs
根据,应用程序工厂是好的,因为:
before\u request()
和before\u request()
在接下来的段落中,我将展示我是如何将应用程序工厂模式用于uWSGI应用程序服务器和nginx的(我只使用了这些,但我可以尝试帮助您使用其他服务器进行配置)
应用程序工厂
因此,假设您的应用程序位于文件夹your application中,其中有\uuuu init\uuuuuuuy.py
文件:
import os
from flask import Flask
def create_app(cfg=None):
app = Flask(__name__)
load_config(app, cfg)
# import all route modules
# and register blueprints
return app
def load_config(app, cfg):
# Load a default configuration file
app.config.from_pyfile('config/default.cfg')
# If cfg is empty try to load config file from environment variable
if cfg is None and 'YOURAPPLICATION_CFG' in os.environ:
cfg = os.environ['YOURAPPLICATION_CFG']
if cfg is not None:
app.config.from_pyfile(cfg)
现在,您需要一个文件来创建应用程序的实例:
from yourapplication import create_app
app = create_app()
if __name__ == "__main__":
app.run()
在上面的代码中,我假设有一个环境变量设置了配置文件的路径,但是您可以将配置路径指定给工厂,如下所示:
app = create_app('config/prod.cfg')
def load_config(app, env):
app.config.from_pyfile('config/default.cfg')
var = "YOURAPPLICATION_ENV"
if env is None and var in os.environ:
env = os.environ[var]
if env in CONFIG_FILES:
app.config.from_pyfile(CONFIG_FILES[env])
[uwsgi]
plugins=python
vhost=true
socket=/tmp/yourapplication.sock
env = YOURAPPLICATION_ENV=production
logto = /var/www/yourapplication/logs/uwsgi.log
或者,您可以使用类似于字典的工具,其中包含环境和相应的配置文件:
CONFIG_FILES = {'development': 'config/development.cfg',
'test' : 'config/test.cfg',
'production' : 'config/production.cfg' }
在这种情况下,load\u config
函数如下所示:
app = create_app('config/prod.cfg')
def load_config(app, env):
app.config.from_pyfile('config/default.cfg')
var = "YOURAPPLICATION_ENV"
if env is None and var in os.environ:
env = os.environ[var]
if env in CONFIG_FILES:
app.config.from_pyfile(CONFIG_FILES[env])
[uwsgi]
plugins=python
vhost=true
socket=/tmp/yourapplication.sock
env = YOURAPPLICATION_ENV=production
logto = /var/www/yourapplication/logs/uwsgi.log
Nginx和uWSGI
以下是nginx的配置文件示例:
server {
listen 80;
server_name yourapplication.com;
access_log /var/www/yourapplication/logs/access.log;
error_log /var/www/yourapplication/logs/error.log;
location / {
try_files $uri @flask;
}
location @flask {
include uwsgi_params;
uwsgi_pass unix:/tmp/yourapplication.sock;
# /env is the virtualenv directory
uwsgi_param UWSGI_PYHOME /var/www/yourapplication/env;
# the path where the module run is located
uwsgi_param UWSGI_CHDIR /var/www/yourapplication;
# the name of the module to be called
uwsgi_param UWSGI_MODULE run;
# the variable declared in the run module, an instance of Flask
uwsgi_param UWSGI_CALLABLE app;
}
}
uWSGI配置文件如下所示:
app = create_app('config/prod.cfg')
def load_config(app, env):
app.config.from_pyfile('config/default.cfg')
var = "YOURAPPLICATION_ENV"
if env is None and var in os.environ:
env = os.environ[var]
if env in CONFIG_FILES:
app.config.from_pyfile(CONFIG_FILES[env])
[uwsgi]
plugins=python
vhost=true
socket=/tmp/yourapplication.sock
env = YOURAPPLICATION_ENV=production
logto = /var/www/yourapplication/logs/uwsgi.log
如何在请求前()和请求后()使用
这些函数的问题在于,如果您在其他模块中调用它们,则在应用程序实例化之前,无法导入这些模块。同样,政府也有话要说:
缺点是在导入时不能在蓝图中使用应用程序对象。但是,您可以在请求中使用它。如何使用配置文件访问应用程序?使用当前的应用程序:
或您可以考虑,然后您可以导入类,而不存在任何存在的烧瓶实例,因为类扩展只会在创建后使用Fulk实例。
所以,刚刚意识到这一点-我可以通过使用CurrnEnApp->在其他位置使用应用程序。这似乎还有很长的路要走-我可能会被要求完全避免路由装饰器,并手动设置路由-然后我可以忽略导入顺序-我认为?您可以使用类作为视图,而不是带有装饰器的函数。看一看,和。另外,请看一看并了解如何组织应用程序。“但是,请注意,如果您使用的是测试请求上下文,则对于after_request()函数,before_request()函数不会自动调用相同的函数。”no before/after request函数适用于测试请求上下文,而不是工厂函数。但是,您仍然需要将其挂接到工厂或在实例化应用程序后定义它们。在设置其他扩展(如Flask Admin)时使用应用程序配置如何?例如,如果我想让我的apps config的值指示管理员视图是否显示编辑选项(can\u create=current\u app.config.get('SOME\u config'))?或者对于可以从多个位置调用但需要应用程序配置的实用程序功能?在这种情况下,当前的应用程序是空的,因为我们在请求上下文之外。“有什么办法处理这样的案件吗?”罗伯托说。