瓶踪暇影——使用Flask开发web应用琐记(1)

我最近也在思考这个问题“多个 app 部署在同一服务器下”

看到你这篇文章介绍,我也尝试部署了一下,发现自己理解的比较混乱

希望能得到你的帮助,能指点一二,对于这种部署多应用目录结构如何划分,以及配置方面迷惑

非常感谢!

不知不觉间,已经一年没写博客了。看来写博客这活太重量级,还是微博上灌水省心啊。

之前在一个项目里用 Flask 开发其中的 Web 部分,有些小心得,插空整理出来放到博客上权当备忘。

里面的代码都来自实际项目。

多个 app 部署在同一服务器下

有时我们需要把多个独立的 Flask 应用部署在同一服务器下,根据 URL 前缀转到不同的应用,这时候可以用 werkzeug 的 DispatcherMiddleware 来实现 app 串接。

from werkzeug.wsgi import DispatcherMiddleware

dummy_app = Flask(__name__)

@dummy_app.route('/')
def index():
    return redirect('/uc')

import uc.ucweb
import zs.zsweb

all_apps = ((None, dummy_app), ('/uc', uc.ucweb.app), ('/zs', zs.zsweb.app))

main_app = [app for (mp, app) in all_apps if not mp][0]
sub_apps = dict(((mp, app) for (mp, app) in all_apps if mp))
app = DispatcherMiddleware(main_app, sub_apps)

这个例子中创建了一个占位的 Flask 对象专用于转跳,这是项目中的某个特殊需求所致。一般来说把 all_apps 中想挂载到根路径的 app 对应的 URL 前缀设为 None 即可。后面的代码会根据 URL 前缀来把各应用自动分配给 DispatcherMiddleware 的构造函数。

instance_path 和配置文件读取

Flask 提供了从 Python 对象或者 .py 文件中读取配置的功能。但是因为 Flask 没有像 Pylons 那样使用 paster 来生成项目的初始结构,所以实际项目中这部分代码还是要自己写的。

import defaultcfg

kwargs = {}
kwargs['instance_relative_config'] = True

try:
    instance_folder = os.environ['INSTANCE_FOLDER']
    kwargs['instance_path'] = instance_folder
except KeyError:
    pass

app_name = __name__.split('.')[0]

deploy_mode = 'production'
try:
    if os.environ['DEPLOY_MODE'].upper() == 'DEBUG':
        deploy_mode = 'debug'
except KeyError:
    pass

app = Flask(app_name, **kwargs)

app.config.from_object(defaultcfg)
app.config.from_pyfile('common_%s.py' % (deploy_mode), silent=True)
app.config.from_pyfile('%s_%s.py' % (app_name, deploy_mode), silent=True)

字典 kwargs 将要传给Flask 类构造函数的参数,其中 instance_relative_config 表示是否从实例路径(instance path)中读取配置文件,这样可以把配置与程序本身的路径分离,并且不需要硬编码其路径。当然,程序的运行时数据(比如程序自己的本地数据库、 cache 过来的一些参数表等)也应该放到实例路径中去,具体做法在此不多说。

接下来,看 instance_path 的实际路径是否已在环境变量中设置(其实从 argv 中读取命令行参数也是个不错的主意),没有则取 Flask 的默认值。

app_name 按 Flask 文档中的建议取 __name__ 的第一段。

在构造了 app 对象后,首先从 defaultcfg 对象中读取配置的默认值,然后读取公共配置文件 common_<部署模式>.py ,最后读取应用相关的配置文件 <程序名>_<部署模式>.py 。由于之前设置为从 instance_path 中读取配置文件,因此可以把不同 app 的 instance_path 指定到同一个目录,这样多个 app 的公共配置部分(比如日志设置、公共的数据库设置等)就可以只写一份,而各 app 自己的独有配置则放到各自的配置文件中去。生产系统的配置和调试系统的配置则通过表示部署模式的 deploy_mode 来区分开。