动机
最近我们机器人后台系统承接的业务越来越多,除了机器人本身的后台,还有门禁系统、广告系统等的后台,都需要单独的登录流程(门禁还细分PC端小区物业登录和app端业主登录),但是我发现flask-login跟Flask app是一一对应关系,即一个app内只可能存在一个login manager,所以为了运行多个login manager,只能运行多个app
app dispatch技术
Application Dispatching是WSGI工具箱werkzeug提供的一种技术,目的是将多个Flask应用按URL前缀组合成一个应用
class DispatcherMiddleware(__builtin__.object)
| Allows one to mount middlewares or applications in a WSGI application.
| This is useful if you want to combine multiple WSGI applications::
|
| app = DispatcherMiddleware(app, {
| '/app2': app2,
| '/app3': app3
| })实现
官方文档的示例不完整,而且就两级嵌套,不符合我们3级业务的需求(机器人登录/门禁登录/门禁管理员登录),所以决定自己实现一下
目录结构
nest
├── test_app_dispatch.py
├── ad
│ └── __init__.py
└── yeelink
├── __init__.py
└── admin
└── __init__.py
每一层组合,或者说嵌套,其模式是一模一样的,类似递归/分形,所以我只把nest跟yeelink/ad的组合代码贴出来
nest/test_app_dispatch.py内容
#encoding = utf-8
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
from flask import Flask
from yeelink import app as app_yeelink
from ad import app as app_ad
app = Flask(__name__)
app.secret_key = 'topLevel'
@app.route('/')
def index():
return 'Hello top level!'
app = DispatcherMiddleware(app,{
'/yeelink': app_yeelink,
'/ad': app_ad
})
if __name__ == '__main__':
run_simple('localhost', 5000, app,
use_reloader=True, use_debugger=True, use_evalex=True)nest/yeelink/__init__.py
#encoding = utf-8
from werkzeug.wsgi import DispatcherMiddleware
from flask import Flask,current_app,request,redirect,session,flash,url_for
from admin import app as app_admin
app = Flask(__name__)
app.secret_key = 'yeelink'
@app.route('/')
def index():
return 'yeelink Page'
app = DispatcherMiddleware(app,{
'/admin': app_admin
})
注意
DispatcherMiddleware实例不是Flask实例,没有route装饰器,所以该类的调用一定要放到所有@app.route语句的后面,否则会报以下错误:
Traceback (most recent call last):
File "test_app_dispatch.py", line 17, in <module>
@app.route('/')
AttributeError: 'DispatcherMiddleware' object has no attribute 'route'因为顶层wsgi对象在import所有模块时,是按顺序执行模块语句的,所以当import执行到app.route时,app绑定的仍是Flask实例,但是执行DispatcherMiddleware后,app绑定的已经是DispatcherMiddleware实例了,最终由run_simple()方法运行该组合后的实例。
总结
app dispatch技术实现了app的隔离(独立的login manager、secret_key等),同时让每层业务系统都能模块化(只关心自己的URL部分),很有用。