توزیع برنامه¶
توزیع برنامه، فرآیند ترکیب چندین برنامه فلاسک در سطح 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)