CINXE.COM

Application Dispatching — Flask Documentation (3.1.x)

<!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 &#8212; Flask Documentation (3.1.x)</title> <link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=4f649999" /> <link rel="stylesheet" type="text/css" href="../../_static/flask.css?v=b87c8d14" /> <script src="../../_static/documentation_options.js?v=d71c4578"></script> <script src="../../_static/doctools.js?v=9bcbadda"></script> <script src="../../_static/sphinx_highlight.js?v=dc90522c"></script> <link rel="canonical" href="https://flask.palletsprojects.com/en/stable/patterns/appdispatch/" /> <link rel="icon" href="../../_static/shortcut-icon.png"/> <link rel="index" title="Index" href="../../genindex/" /> <link rel="search" title="Search" href="../../search/" /> <link rel="next" title="Using URL Processors" href="../urlprocessors/" /> <link rel="prev" title="Application Factories" href="../appfactories/" /> <script async type="text/javascript" src="/_/static/javascript/readthedocs-addons.js"></script><meta name="readthedocs-project-slug" content="flask" /><meta name="readthedocs-version-slug" content="stable" /><meta name="readthedocs-resolver-filename" content="/patterns/appdispatch/" /><meta name="readthedocs-http-status" content="200" /></head><body> <div class="related" role="navigation" aria-label="Related"> <h3>Navigation</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../../genindex/" title="General Index" accesskey="I">index</a></li> <li class="right" > <a href="../../py-modindex/" title="Python Module Index" >modules</a> |</li> <li class="right" > <a href="../urlprocessors/" title="Using URL Processors" accesskey="N">next</a> |</li> <li class="right" > <a href="../appfactories/" title="Application Factories" accesskey="P">previous</a> |</li> <li class="nav-item nav-item-0"><a href="../../">Flask Documentation (3.1.x)</a> &#187;</li> <li class="nav-item nav-item-1"><a href="../" accesskey="U">Patterns for Flask</a> &#187;</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/"><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/"><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="nn">flask</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">&#39;/&#39;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">hello_world</span><span class="p">():</span> <span class="k">return</span> <span class="s1">&#39;Hello World!&#39;</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="nn">werkzeug.middleware.dispatcher</span> <span class="kn">import</span> <span class="n">DispatcherMiddleware</span> <span class="kn">from</span> <span class="nn">frontend_app</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="nn">backend_app</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">&#39;/backend&#39;</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/"><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="nn">threading</span> <span class="kn">import</span> <span class="n">Lock</span> <span class="k">class</span> <span class="nc">SubdomainDispatcher</span><span class="p">:</span> <span class="k">def</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="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">&#39;:&#39;</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">&#39;Configuration error&#39;</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">&#39;.&#39;</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="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">&#39;HTTP_HOST&#39;</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="nn">myapplication</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="nn">werkzeug.exceptions</span> <span class="kn">import</span> <span class="n">NotFound</span> <span class="k">def</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">&#39;example.com&#39;</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="nn">threading</span> <span class="kn">import</span> <span class="n">Lock</span> <span class="kn">from</span> <span class="nn">wsgiref.util</span> <span class="kn">import</span> <span class="n">shift_path_info</span> <span class="k">class</span> <span class="nc">PathDispatcher</span><span class="p">:</span> <span class="k">def</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="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="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="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">&quot;PATH_INFO&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;/&quot;</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="nn">myapplication</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="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="../../"> <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="../../">Overview</a> <ul> <li><a href="../">Patterns for Flask</a> <ul> <li>Previous: <a href="../appfactories/" title="previous chapter">Application Factories</a> <li>Next: <a href="../urlprocessors/" 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/" 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"> &#169; Copyright 2010 Pallets. Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3. </div> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10