flask源码解析之DispatcherMiddleware

DispatcherMiddleware作用

  实现多app的应用,完成路由分发的功能

如何使用

from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
from flask import Flask, current_app,request

app1 = Flask('app01')

app2 = Flask('app02')


@app1.route('/index/')
def index():
    return "app01"


@app2.route('/index2/')
def index2():
    """
    存在的问题:
            def __call__(self, environ, start_response):
        # 获取当前请求的URL,script == '/index/'
        script = environ.get('PATH_INFO', '')
        path_info = ''
        # '/' 在 '/index/' 中
        while '/' in script:
            # self.mounts == {'/sec': app2,}, '/' 不在 self.mounts 中
            if script in self.mounts:
                app = self.mounts[script]
                break
            script, last_item = script.rsplit('/', 1)
            path_info = '/%s%s' % (last_item, path_info)
        else:
            app = self.mounts.get(script, self.app)
        original_script_name = environ.get('SCRIPT_NAME', '')
        environ['SCRIPT_NAME'] = original_script_name + script
        environ['PATH_INFO'] = path_info  #  这里得到的知识不包含前缀的url,那这样不是就丢失了吗
        return app(environ, start_response)
    :return:
    """
    print(request.full_path) # 得到的是 /index2/? 且没有request.path_info
    return "app2"


# http://www.oldboyedu.com/index
# http://www.oldboyedu.com/sec/index2
dm = DispatcherMiddleware(app1, {
    '/sec': app2,
})

if __name__ == "__main__":
    run_simple('localhost', 5000, dm)

注意事项:

  在DispatcherMiddleware类的实例参数中,第一个参数不能是一个字典,即第一个参数只能是一个app实例,即没有前缀的。但是后面的APP实例都可以是有前缀的app,存放至字典中

源码分析

请求每次进来执行DispatcherMiddleware的__call__方法,实现分发的原理是:获取本次请求的url,对url进行分割,直到分割出来的部分url(前缀)在保存了分发路由关系字典的self.mounts中时,分割结束,根据前缀找到要执行的函数,并做后续的操作。

posted on 2018-09-12 21:23  云烟||成雨  阅读(1812)  评论(0编辑  收藏  举报