You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
2.2 KiB
67 lines
2.2 KiB
5 years ago
|
"""
|
||
|
Application Dispatcher
|
||
|
======================
|
||
|
|
||
|
This middleware creates a single WSGI application that dispatches to
|
||
|
multiple other WSGI applications mounted at different URL paths.
|
||
|
|
||
|
A common example is writing a Single Page Application, where you have a
|
||
|
backend API and a frontend written in JavaScript that does the routing
|
||
|
in the browser rather than requesting different pages from the server.
|
||
|
The frontend is a single HTML and JS file that should be served for any
|
||
|
path besides "/api".
|
||
|
|
||
|
This example dispatches to an API app under "/api", an admin app
|
||
|
under "/admin", and an app that serves frontend files for all other
|
||
|
requests::
|
||
|
|
||
|
app = DispatcherMiddleware(serve_frontend, {
|
||
|
'/api': api_app,
|
||
|
'/admin': admin_app,
|
||
|
})
|
||
|
|
||
|
In production, you might instead handle this at the HTTP server level,
|
||
|
serving files or proxying to application servers based on location. The
|
||
|
API and admin apps would each be deployed with a separate WSGI server,
|
||
|
and the static files would be served directly by the HTTP server.
|
||
|
|
||
|
.. autoclass:: DispatcherMiddleware
|
||
|
|
||
|
:copyright: 2007 Pallets
|
||
|
:license: BSD-3-Clause
|
||
|
"""
|
||
|
|
||
|
|
||
|
class DispatcherMiddleware(object):
|
||
|
"""Combine multiple applications as a single WSGI application.
|
||
|
Requests are dispatched to an application based on the path it is
|
||
|
mounted under.
|
||
|
|
||
|
:param app: The WSGI application to dispatch to if the request
|
||
|
doesn't match a mounted path.
|
||
|
:param mounts: Maps path prefixes to applications for dispatching.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, app, mounts=None):
|
||
|
self.app = app
|
||
|
self.mounts = mounts or {}
|
||
|
|
||
|
def __call__(self, environ, start_response):
|
||
|
script = environ.get("PATH_INFO", "")
|
||
|
path_info = ""
|
||
|
|
||
|
while "/" in script:
|
||
|
if script in self.mounts:
|
||
|
app = self.mounts[script]
|
||
|
break
|
||
|
|
||
|
script, last_item = script.rsplit("/", 1)
|
||
|
path_info = "/%s%s" % (last_item, path_info)
|
||
|
else:
|
||
|
app = self.mounts.get(script, self.app)
|
||
|
|
||
|
original_script_name = environ.get("SCRIPT_NAME", "")
|
||
|
environ["SCRIPT_NAME"] = original_script_name + script
|
||
|
environ["PATH_INFO"] = path_info
|
||
|
return app(environ, start_response)
|