- en
- Language: ru
- Documentation version: 1.1.x
Диспетчеризация приложений¶
Диспетчеризация приложений - это процесс объединения нескольких приложений Flask на уровне WSGI. Вы можете объединять не только приложения Flask, но и любые приложения WSGI. Это позволит вам запускать Django и Flask приложения в одном интерпретаторе бок о бок, если вы захотите. Полезность этого зависит от того, как приложения работают внутри.
Принципиальное отличие от module approach заключается в том, что в этом случае вы запускаете одно и то же или разные приложения 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
не предназначен для использования в производстве. Используйте full-blown WSGI server.
Чтобы использовать интерактивный отладчик, отладка должна быть включена как на приложении, так и на простом сервере. Вот пример «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
})
Отправка по поддоменам¶
Иногда вам может понадобиться использовать несколько экземпляров одного и того же приложения с разными конфигурациями. Если приложение создается внутри функции, и вы можете вызвать эту функцию для его инстанцирования, это очень просто реализовать. Для того чтобы разработать приложение, поддерживающее создание новых экземпляров в функциях, ознакомьтесь с паттерном Заводы по производству приложений.
Очень распространенным примером является создание приложений для каждого поддомена. Например, вы настраиваете свой веб-сервер на отправку всех запросов для всех поддоменов в ваше приложение, а затем используете информацию о поддоменах для создания пользовательских экземпляров. Как только вы настроите свой сервер на прослушивание всех поддоменов, вы можете использовать очень простое приложение 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)
Большая разница между этим и поддоменным вариантом заключается в том, что этот вариант возвращается к другому приложению, если функция создателя возвращает 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)