| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | Application Dispatching
 | 
					
						
							|  |  |  | =======================
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | Application dispatching is the process of combining multiple Flask
 | 
					
						
							| 
									
										
										
										
											2016-04-02 05:12:25 +08:00
										 |  |  | applications on the WSGI level.  You can combine not only Flask
 | 
					
						
							|  |  |  | applications but any WSGI application.  This would allow you to run a
 | 
					
						
							|  |  |  | Django and a Flask application in the same interpreter side by side if
 | 
					
						
							|  |  |  | you want.  The usefulness of this depends on how the applications work
 | 
					
						
							|  |  |  | internally.
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-05 03:57:14 +08:00
										 |  |  | The fundamental difference from :doc:`packages` is that in this case you
 | 
					
						
							|  |  |  | are running the same or different Flask applications that are entirely
 | 
					
						
							|  |  |  | isolated from each other. They run different configurations and are
 | 
					
						
							|  |  |  | dispatched on the WSGI level.
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-26 02:09:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Working with this Document
 | 
					
						
							|  |  |  | --------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-05 03:57:14 +08:00
										 |  |  | Each of the techniques and examples below results in an ``application``
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  | object that can be run with any WSGI server. For development, use the
 | 
					
						
							|  |  |  | ``flask run`` command to start a development server. For production, see
 | 
					
						
							|  |  |  | :doc:`/deploying/index`.
 | 
					
						
							| 
									
										
										
										
											2011-06-26 02:09:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  | .. code-block:: python
 | 
					
						
							| 
									
										
										
										
											2012-03-16 16:38:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from flask import Flask
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     app = Flask(__name__)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @app.route('/')
 | 
					
						
							|  |  |  |     def hello_world():
 | 
					
						
							|  |  |  |         return 'Hello World!'
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-26 02:09:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | Combining Applications
 | 
					
						
							|  |  |  | ----------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you have entirely separated applications and you want them to work next
 | 
					
						
							|  |  |  | to each other in the same Python interpreter process you can take
 | 
					
						
							|  |  |  | advantage of the :class:`werkzeug.wsgi.DispatcherMiddleware`.  The idea
 | 
					
						
							|  |  |  | here is that each Flask application is a valid WSGI application and they
 | 
					
						
							| 
									
										
										
										
											2016-04-02 05:12:25 +08:00
										 |  |  | are combined by the dispatcher middleware into a larger one that is
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | dispatched based on prefix.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 12:19:02 +08:00
										 |  |  | For example you could have your main application run on ``/`` and your
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  | backend interface on ``/backend``.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .. code-block:: python
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-23 23:19:40 +08:00
										 |  |  |     from werkzeug.middleware.dispatcher import DispatcherMiddleware
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  |     from frontend_app import application as frontend
 | 
					
						
							|  |  |  |     from backend_app import application as backend
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     application = DispatcherMiddleware(frontend, {
 | 
					
						
							| 
									
										
										
										
											2019-09-23 23:19:40 +08:00
										 |  |  |         '/backend': backend
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  |     })
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Dispatch by Subdomain
 | 
					
						
							|  |  |  | ---------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | Sometimes you might want to use multiple instances of the same application
 | 
					
						
							|  |  |  | with different configurations.  Assuming the application is created inside
 | 
					
						
							| 
									
										
										
										
											2012-01-24 03:12:56 +08:00
										 |  |  | a function and you can call that function to instantiate it, that is
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | really easy to implement.  In order to develop your application to support
 | 
					
						
							|  |  |  | creating new instances in functions have a look at the
 | 
					
						
							| 
									
										
										
										
											2020-04-05 03:57:14 +08:00
										 |  |  | :doc:`appfactories` pattern.
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | A very common example would be creating applications per subdomain.  For
 | 
					
						
							|  |  |  | instance you configure your webserver to dispatch all requests for all
 | 
					
						
							|  |  |  | subdomains to your application and you then use the subdomain information
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | to create user-specific instances.  Once you have your server set up to
 | 
					
						
							|  |  |  | listen on all subdomains you can use a very simple WSGI application to do
 | 
					
						
							|  |  |  | the dynamic application creation.
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 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
 | 
					
						
							| 
									
										
										
										
											2012-04-19 03:54:04 +08:00
										 |  |  | delegates it to your Flask application.  If that application does not
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  | exist yet, it is dynamically created and remembered.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .. code-block:: python
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from threading import Lock
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 20:57:08 +08:00
										 |  |  |     class SubdomainDispatcher:
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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:
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  |                     app = self.create_app(subdomain)
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  |                     self.instances[subdomain] = app
 | 
					
						
							|  |  |  |                 return app
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __call__(self, environ, start_response):
 | 
					
						
							|  |  |  |             app = self.get_application(environ['HTTP_HOST'])
 | 
					
						
							|  |  |  |             return app(environ, start_response)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  | This dispatcher can then be used like this:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .. code-block:: python
 | 
					
						
							| 
									
										
										
										
											2011-03-15 02:19:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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)
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Dispatch by Path
 | 
					
						
							|  |  |  | ----------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Dispatching by a path on the URL is very similar.  Instead of looking at
 | 
					
						
							| 
									
										
										
										
											2014-11-05 12:23:47 +08:00
										 |  |  | the ``Host`` header to figure out the subdomain one simply looks at the
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  | request path up to the first slash.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .. code-block:: python
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from threading import Lock
 | 
					
						
							| 
									
										
										
										
											2023-08-13 20:12:25 +08:00
										 |  |  |     from wsgiref.util import shift_path_info
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 20:57:08 +08:00
										 |  |  |     class PathDispatcher:
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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):
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  |             app = self.get_application(_peek_path_info(environ))
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  |             if app is not None:
 | 
					
						
							| 
									
										
										
										
											2023-08-13 20:12:25 +08:00
										 |  |  |                 shift_path_info(environ)
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  |             else:
 | 
					
						
							|  |  |  |                 app = self.default_app
 | 
					
						
							|  |  |  |             return app(environ, start_response)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-13 20:12:25 +08:00
										 |  |  |     def _peek_path_info(environ):
 | 
					
						
							|  |  |  |         segments = environ.get("PATH_INFO", "").lstrip("/").split("/", 1)
 | 
					
						
							|  |  |  |         if segments:
 | 
					
						
							|  |  |  |             return segments[0]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return None
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | The big difference between this and the subdomain one is that this one
 | 
					
						
							| 
									
										
										
										
											2023-08-17 05:25:53 +08:00
										 |  |  | falls back to another application if the creator function returns ``None``.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .. code-block:: python
 | 
					
						
							| 
									
										
										
										
											2011-03-15 04:44:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 18:44:28 +08:00
										 |  |  |     application = PathDispatcher(default_app, make_app)
 |