272 lines
No EOL
23 KiB
HTML
272 lines
No EOL
23 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html lang="en" data-content_root="../">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Application Dispatching — Flask Documentation (3.2.x)</title>
|
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=6625fa76" />
|
|
<link rel="stylesheet" type="text/css" href="../_static/flask.css?v=b87c8d14" />
|
|
<script src="../_static/documentation_options.js?v=56528222"></script>
|
|
<script src="../_static/doctools.js?v=9bcbadda"></script>
|
|
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
|
|
<script data-project="flask" data-version="3.2.x" src="../_static/describe_version.js?v=fa7f30d0"></script>
|
|
<link rel="icon" href="../_static/shortcut-icon.png"/>
|
|
<link rel="index" title="Index" href="../genindex.html" />
|
|
<link rel="search" title="Search" href="../search.html" />
|
|
<link rel="next" title="Using URL Processors" href="urlprocessors.html" />
|
|
<link rel="prev" title="Application Factories" href="appfactories.html" />
|
|
</head><body>
|
|
<div class="related" role="navigation" aria-label="Related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../genindex.html" title="General Index"
|
|
accesskey="I">index</a></li>
|
|
<li class="right" >
|
|
<a href="../py-modindex.html" title="Python Module Index"
|
|
>modules</a> |</li>
|
|
<li class="right" >
|
|
<a href="urlprocessors.html" title="Using URL Processors"
|
|
accesskey="N">next</a> |</li>
|
|
<li class="right" >
|
|
<a href="appfactories.html" title="Application Factories"
|
|
accesskey="P">previous</a> |</li>
|
|
<li class="nav-item nav-item-0"><a href="../index.html">Flask Documentation (3.2.x)</a> »</li>
|
|
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
|
<li class="nav-item nav-item-this"><a href="">Application Dispatching</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="document">
|
|
<div class="documentwrapper">
|
|
<div class="bodywrapper">
|
|
<div class="body" role="main">
|
|
|
|
<section id="application-dispatching">
|
|
<h1>Application Dispatching<a class="headerlink" href="#application-dispatching" title="Link to this heading">¶</a></h1>
|
|
<p>Application dispatching is the process of combining multiple Flask
|
|
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.</p>
|
|
<p>The fundamental difference from <a class="reference internal" href="packages.html"><span class="doc">Large Applications as Packages</span></a> 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.</p>
|
|
<section id="working-with-this-document">
|
|
<h2>Working with this Document<a class="headerlink" href="#working-with-this-document" title="Link to this heading">¶</a></h2>
|
|
<p>Each of the techniques and examples below results in an <code class="docutils literal notranslate"><span class="pre">application</span></code>
|
|
object that can be run with any WSGI server. For development, use the
|
|
<code class="docutils literal notranslate"><span class="pre">flask</span> <span class="pre">run</span></code> command to start a development server. For production, see
|
|
<a class="reference internal" href="../deploying/index.html"><span class="doc">Deploying to Production</span></a>.</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">Flask</span>
|
|
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
|
|
|
|
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">hello_world</span><span class="p">():</span>
|
|
<span class="k">return</span> <span class="s1">'Hello World!'</span>
|
|
</pre></div>
|
|
</div>
|
|
</section>
|
|
<section id="combining-applications">
|
|
<h2>Combining Applications<a class="headerlink" href="#combining-applications" title="Link to this heading">¶</a></h2>
|
|
<p>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 <code class="xref py py-class docutils literal notranslate"><span class="pre">werkzeug.wsgi.DispatcherMiddleware</span></code>. The idea
|
|
here is that each Flask application is a valid WSGI application and they
|
|
are combined by the dispatcher middleware into a larger one that is
|
|
dispatched based on prefix.</p>
|
|
<p>For example you could have your main application run on <code class="docutils literal notranslate"><span class="pre">/</span></code> and your
|
|
backend interface on <code class="docutils literal notranslate"><span class="pre">/backend</span></code>.</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.middleware.dispatcher</span><span class="w"> </span><span class="kn">import</span> <span class="n">DispatcherMiddleware</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">frontend_app</span><span class="w"> </span><span class="kn">import</span> <span class="n">application</span> <span class="k">as</span> <span class="n">frontend</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">backend_app</span><span class="w"> </span><span class="kn">import</span> <span class="n">application</span> <span class="k">as</span> <span class="n">backend</span>
|
|
|
|
<span class="n">application</span> <span class="o">=</span> <span class="n">DispatcherMiddleware</span><span class="p">(</span><span class="n">frontend</span><span class="p">,</span> <span class="p">{</span>
|
|
<span class="s1">'/backend'</span><span class="p">:</span> <span class="n">backend</span>
|
|
<span class="p">})</span>
|
|
</pre></div>
|
|
</div>
|
|
</section>
|
|
<section id="dispatch-by-subdomain">
|
|
<h2>Dispatch by Subdomain<a class="headerlink" href="#dispatch-by-subdomain" title="Link to this heading">¶</a></h2>
|
|
<p>Sometimes you might want to use multiple instances of the same application
|
|
with different configurations. Assuming the application is created inside
|
|
a function and you can call that function to instantiate it, that is
|
|
really easy to implement. In order to develop your application to support
|
|
creating new instances in functions have a look at the
|
|
<a class="reference internal" href="appfactories.html"><span class="doc">Application Factories</span></a> pattern.</p>
|
|
<p>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
|
|
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.</p>
|
|
<p>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.</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">threading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Lock</span>
|
|
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">SubdomainDispatcher</span><span class="p">:</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">domain</span><span class="p">,</span> <span class="n">create_app</span><span class="p">):</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">domain</span> <span class="o">=</span> <span class="n">domain</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">create_app</span> <span class="o">=</span> <span class="n">create_app</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">Lock</span><span class="p">()</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span> <span class="o">=</span> <span class="p">{}</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_application</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">host</span><span class="p">):</span>
|
|
<span class="n">host</span> <span class="o">=</span> <span class="n">host</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">':'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
|
|
<span class="k">assert</span> <span class="n">host</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">domain</span><span class="p">),</span> <span class="s1">'Configuration error'</span>
|
|
<span class="n">subdomain</span> <span class="o">=</span> <span class="n">host</span><span class="p">[:</span><span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">domain</span><span class="p">)]</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span>
|
|
<span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="p">[</span><span class="n">subdomain</span><span class="p">]</span> <span class="o">=</span> <span class="n">app</span>
|
|
<span class="k">return</span> <span class="n">app</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_application</span><span class="p">(</span><span class="n">environ</span><span class="p">[</span><span class="s1">'HTTP_HOST'</span><span class="p">])</span>
|
|
<span class="k">return</span> <span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>This dispatcher can then be used like this:</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">myapplication</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_app</span><span class="p">,</span> <span class="n">get_user_for_subdomain</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.exceptions</span><span class="w"> </span><span class="kn">import</span> <span class="n">NotFound</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">make_app</span><span class="p">(</span><span class="n">subdomain</span><span class="p">):</span>
|
|
<span class="n">user</span> <span class="o">=</span> <span class="n">get_user_for_subdomain</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="c1"># if there is no user for that subdomain we still have</span>
|
|
<span class="c1"># to return a WSGI application that handles that request.</span>
|
|
<span class="c1"># We can then just return the NotFound() exception as</span>
|
|
<span class="c1"># application which will render a default 404 page.</span>
|
|
<span class="c1"># You might also redirect the user to the main page then</span>
|
|
<span class="k">return</span> <span class="n">NotFound</span><span class="p">()</span>
|
|
|
|
<span class="c1"># otherwise create the application for the specific user</span>
|
|
<span class="k">return</span> <span class="n">create_app</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
|
|
|
<span class="n">application</span> <span class="o">=</span> <span class="n">SubdomainDispatcher</span><span class="p">(</span><span class="s1">'example.com'</span><span class="p">,</span> <span class="n">make_app</span><span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
</section>
|
|
<section id="dispatch-by-path">
|
|
<h2>Dispatch by Path<a class="headerlink" href="#dispatch-by-path" title="Link to this heading">¶</a></h2>
|
|
<p>Dispatching by a path on the URL is very similar. Instead of looking at
|
|
the <code class="docutils literal notranslate"><span class="pre">Host</span></code> header to figure out the subdomain one simply looks at the
|
|
request path up to the first slash.</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">threading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Lock</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">wsgiref.util</span><span class="w"> </span><span class="kn">import</span> <span class="n">shift_path_info</span>
|
|
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">PathDispatcher</span><span class="p">:</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default_app</span><span class="p">,</span> <span class="n">create_app</span><span class="p">):</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">default_app</span> <span class="o">=</span> <span class="n">default_app</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">create_app</span> <span class="o">=</span> <span class="n">create_app</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">Lock</span><span class="p">()</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span> <span class="o">=</span> <span class="p">{}</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_application</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prefix</span><span class="p">):</span>
|
|
<span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="p">[</span><span class="n">prefix</span><span class="p">]</span> <span class="o">=</span> <span class="n">app</span>
|
|
<span class="k">return</span> <span class="n">app</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_application</span><span class="p">(</span><span class="n">_peek_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">))</span>
|
|
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="n">shift_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">)</span>
|
|
<span class="k">else</span><span class="p">:</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default_app</span>
|
|
<span class="k">return</span> <span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">_peek_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">):</span>
|
|
<span class="n">segments</span> <span class="o">=</span> <span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"PATH_INFO"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">"/"</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">segments</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">segments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
|
|
|
<span class="k">return</span> <span class="kc">None</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The big difference between this and the subdomain one is that this one
|
|
falls back to another application if the creator function returns <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">myapplication</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_app</span><span class="p">,</span> <span class="n">default_app</span><span class="p">,</span> <span class="n">get_user_for_prefix</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">make_app</span><span class="p">(</span><span class="n">prefix</span><span class="p">):</span>
|
|
<span class="n">user</span> <span class="o">=</span> <span class="n">get_user_for_prefix</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">create_app</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
|
|
|
<span class="n">application</span> <span class="o">=</span> <span class="n">PathDispatcher</span><span class="p">(</span><span class="n">default_app</span><span class="p">,</span> <span class="n">make_app</span><span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
</section>
|
|
</section>
|
|
|
|
|
|
<div class="clearer"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<span id="sidebar-top"></span>
|
|
<div class="sphinxsidebar" role="navigation" aria-label="Main">
|
|
<div class="sphinxsidebarwrapper">
|
|
|
|
|
|
<p class="logo"><a href="../index.html">
|
|
<img class="logo" src="../_static/flask-vertical.png" alt="Logo of Flask"/>
|
|
</a></p>
|
|
|
|
|
|
<h3>Contents</h3>
|
|
<ul>
|
|
<li><a class="reference internal" href="#">Application Dispatching</a><ul>
|
|
<li><a class="reference internal" href="#working-with-this-document">Working with this Document</a></li>
|
|
<li><a class="reference internal" href="#combining-applications">Combining Applications</a></li>
|
|
<li><a class="reference internal" href="#dispatch-by-subdomain">Dispatch by Subdomain</a></li>
|
|
<li><a class="reference internal" href="#dispatch-by-path">Dispatch by Path</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li><a href="../index.html">Overview</a>
|
|
<ul>
|
|
<li><a href="index.html">Patterns for Flask</a>
|
|
<ul>
|
|
<li>Previous: <a href="appfactories.html" title="previous chapter">Application Factories</a>
|
|
<li>Next: <a href="urlprocessors.html" title="next chapter">Using URL Processors</a></ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<search id="searchbox" style="display: none" role="search">
|
|
<h3 id="searchlabel">Quick search</h3>
|
|
<div class="searchformwrapper">
|
|
<form class="search" action="../search.html" method="get">
|
|
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
|
|
<input type="submit" value="Go" />
|
|
</form>
|
|
</div>
|
|
</search>
|
|
<script>document.getElementById('searchbox').style.display = "block"</script><div id="ethical-ad-placement"></div>
|
|
</div>
|
|
</div>
|
|
<div class="clearer"></div>
|
|
</div>
|
|
<div class="footer" role="contentinfo">
|
|
© Copyright 2010 Pallets.
|
|
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
|
</div>
|
|
</body>
|
|
</html> |