应用程序调度

应用程序调度是在wsgi级别上组合多个Flask应用程序的过程。您不仅可以组合flask应用程序,还可以组合任何wsgi应用程序。这将允许您在同一个解释器中并排运行django和flask应用程序(如果需要)。这种方法的有效性取决于应用程序如何在内部工作。

大型应用程序包 在这种情况下,您运行的是完全相互隔离的相同或不同的烧瓶应用程序。它们运行不同的配置,并在wsgi级别上调度。

使用此文档

下面的每个技术和示例都会导致 application 对象,可以与任何WSGI服务器一起运行。有关生产,请参见 部署选择 . 为了开发,Werkzeug通过 werkzeug.serving.run_simple() ::

from werkzeug.serving import run_simple
run_simple('localhost', 5000, application, use_reloader=True)

注意 run_simple 不用于生产。使用生产WSGI服务器。看到了吗 部署选择 .

为了使用交互式调试器,必须在应用程序和简单服务器上启用调试。下面是“hello world”示例,其中包含调试和 run_simple ::

from flask import Flask
from werkzeug.serving import run_simple

app = Flask(__name__)
app.debug = True

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    run_simple('localhost', 5000, app,
               use_reloader=True, use_debugger=True, use_evalex=True)

组合应用程序

如果您有完全分离的应用程序,并且希望它们在同一个Python解释器进程中彼此相邻工作,那么您可以利用 werkzeug.wsgi.DispatcherMiddleware . 这里的想法是,每个flask应用程序都是一个有效的wsgi应用程序,它们由调度器中间件组合成一个更大的基于前缀的应用程序。

例如,您可以让主应用程序运行在 / 你的后端接口 /backend ::

from werkzeug.middleware.dispatcher import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend

application = DispatcherMiddleware(frontend, {
    '/backend': backend
})

子域调度

有时,您可能希望使用具有不同配置的同一应用程序的多个实例。假设应用程序是在一个函数内创建的,并且您可以调用该函数来实例化它,这非常容易实现。为了开发支持在函数中创建新实例的应用程序,请查看 应用工厂 模式。

一个非常常见的例子是为每个子域创建应用程序。例如,将Web服务器配置为将所有子域的所有请求分派到应用程序,然后使用子域信息创建用户特定的实例。一旦服务器设置为监听所有子域,就可以使用非常简单的WSGi应用程序来创建动态应用程序。

在这方面,抽象的最佳级别是wsgi层。您可以编写自己的wsgi应用程序,该应用程序查看所收到的请求并将其委托给flask应用程序。如果该应用程序尚不存在,则会动态创建并记住:

from threading import Lock

class SubdomainDispatcher(object):

    def __init__(self, domain, create_app):
        self.domain = domain
        self.create_app = create_app
        self.lock = Lock()
        self.instances = {}

    def get_application(self, host):
        host = host.split(':')[0]
        assert host.endswith(self.domain), 'Configuration error'
        subdomain = host[:-len(self.domain)].rstrip('.')
        with self.lock:
            app = self.instances.get(subdomain)
            if app is None:
                app = self.create_app(subdomain)
                self.instances[subdomain] = app
            return app

    def __call__(self, environ, start_response):
        app = self.get_application(environ['HTTP_HOST'])
        return app(environ, start_response)

然后可以这样使用此调度程序:

from myapplication import create_app, get_user_for_subdomain
from werkzeug.exceptions import NotFound

def make_app(subdomain):
    user = get_user_for_subdomain(subdomain)
    if user is None:
        # if there is no user for that subdomain we still have
        # to return a WSGI application that handles that request.
        # We can then just return the NotFound() exception as
        # application which will render a default 404 page.
        # You might also redirect the user to the main page then
        return NotFound()

    # otherwise create the application for the specific user
    return create_app(user)

application = SubdomainDispatcher('example.com', make_app)

按路径调度

通过URL上的路径进行调度非常类似。不需要查看' ' Host ' ' '头来找出子域,只需查看请求路径直到第一个斜杠:

from threading import Lock
from werkzeug.wsgi import pop_path_info, peek_path_info

class PathDispatcher(object):

    def __init__(self, default_app, create_app):
        self.default_app = default_app
        self.create_app = create_app
        self.lock = Lock()
        self.instances = {}

    def get_application(self, prefix):
        with self.lock:
            app = self.instances.get(prefix)
            if app is None:
                app = self.create_app(prefix)
                if app is not None:
                    self.instances[prefix] = app
            return app

    def __call__(self, environ, start_response):
        app = self.get_application(peek_path_info(environ))
        if app is not None:
            pop_path_info(environ)
        else:
            app = self.default_app
        return app(environ, start_response)

这个和子域一个的最大区别是,如果creator函数返回' ' None ' ',那么这个应用程序将返回到另一个应用程序:

from myapplication import create_app, default_app, get_user_for_prefix

def make_app(prefix):
    user = get_user_for_prefix(prefix)
    if user is not None:
        return create_app(user)

application = PathDispatcher(default_app, make_app)