توزیع برنامه

توزیع برنامه، فرآیند ترکیب چندین برنامه فلاسک در سطح WSGI است. شما می توانید نه تنها برنامه های فلاسک بلکه هر برنامه WSGI را ترکیب کنید. این به شما این امکان را می دهد که در صورت تمایل یک برنامه جنگو و یک فلاسک را در یک مترجم در کنار هم اجرا کنید. سودمندی این امر به نحوه عملکرد داخلی برنامه ها بستگی دارد.

تفاوت اساسی با برنامه های بزرگ به عنوان بسته این است که در این مورد شما برنامه های فلاسک یکسان یا متفاوتی را اجرا می کنید که کاملاً از یکدیگر جدا هستند. آنها پیکربندی های مختلفی را اجرا می کنند و در سطح WSGI توزیع می شوند.

کار با این مستند

Each of the techniques and examples below results in an application object that can be run with any WSGI server. For development, use the flask run command to start a development server. For production, see Deploying to Production.

from flask import Flask

app = Flask(__name__)

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

ترکیب برنامه ها

اگر برنامه‌های کاملاً مجزا دارید و می‌خواهید در یک فرآیند مفسر پایتون در کنار یکدیگر کار کنند، می‌توانید از مزیت werkzeug.wsgi.DispatcherMiddleware استفاده کنید. ایده در اینجا این است که هر برنامه فلاسک یک برنامه WSGI معتبر است و آنها توسط میان افزار توزیع کننده به یک برنامه بزرگتر که بر اساس پیشوند ارسال می شود ترکیب می شوند.

For example you could have your main application run on / and your backend interface on /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
})

توزیع توسط زیر دامنه

گاهی اوقات ممکن است بخواهید از چندین نمونه از یک برنامه با پیکربندی های مختلف استفاده کنید. با فرض اینکه برنامه در داخل یک تابع ایجاد شده است و شما می توانید آن تابع را برای نمونه سازی فراخوانی کنید، پیاده سازی آن واقعا آسان است. به منظور توسعه برنامه خود برای پشتیبانی از ایجاد نمونه های جدید در توابع، به الگوی کارخانه برنامه ها نگاهی بیندازید.

یک مثال بسیار رایج ایجاد برنامه در هر زیر دامنه است. به عنوان مثال، شما وب سرور خود را به گونه ای پیکربندی می کنید که تمام درخواست ها برای همه زیر دامنه ها را به برنامه خود ارسال کند و سپس از اطلاعات زیر دامنه برای ایجاد نمونه های خاص کاربر استفاده می کنید. هنگامی که سرور خود را برای شنود همه زیر دامنه ها تنظیم کردید، می توانید از یک برنامه بسیار ساده WSGI برای ایجاد برنامه پویا استفاده کنید.

The perfect level for abstraction in that regard is the WSGI layer. You write your own WSGI application that looks at the request that comes and delegates it to your Flask application. If that application does not exist yet, it is dynamically created and remembered.

from threading import Lock

class SubdomainDispatcher:

    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)

This dispatcher can then be used like this:

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)

توزیع توسط مسیر

Dispatching by a path on the URL is very similar. Instead of looking at the Host header to figure out the subdomain one simply looks at the request path up to the first slash.

from threading import Lock
from wsgiref.util import shift_path_info

class PathDispatcher:

    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:
            shift_path_info(environ)
        else:
            app = self.default_app
        return app(environ, start_response)

def _peek_path_info(environ):
    segments = environ.get("PATH_INFO", "").lstrip("/").split("/", 1)
    if segments:
        return segments[0]

    return None

The big difference between this and the subdomain one is that this one falls back to another application if the creator function returns 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)