路由到多个顶级和子域的 Flask 应用程序

Bre*_*tin 2 python google-app-engine flask

我有一个应用程序需要多个域指向同一个应用程序并显示不同的数据,但我在所有域中也有相同的“管理”子域,它也根据域显示不同的数据。

一个例子是:

pinetree.com - displays information about pine trees
oaktree.com - displays information about oak trees

admin.pinetree.com - displays admin for managing pine trees
admin.oaktree.com - displays admin for managing oak trees
Run Code Online (Sandbox Code Playgroud)

到目前为止,我发现您需要SERVER_NAME在 Flask 配置中写入(域名)才能在 Flask 中使用子域,但是由于我有许多不同类型的具有唯一域的树,并且一直在添加新树,我不知道如何使用该功能。

此外,我已经看到 GAE flexible 没有多租户,这是我最初想到的在 GAE 上管理多个域的方法。

dav*_*ism 8

如果您有一个包含多个子域的基本域,则应使用在另一个答案中解释的子域匹配。它更直接,因为 Flask 可以推断出更多关于它匹配的 URL。

但是,如果您有多个基本域,则应改用主机匹配。您必须host_matching=True在 app 对象上进行设置,并进行设置,static_host以便static路由知道要从哪个主机提供服务。与子域不同,您无需设置SERVER_NAME. 然后将host选项传递给路由。这与完整域匹配,因此每次都需要写出完整域,而不仅仅是子域。

不幸的是,匹配完整主机也意味着匹配端口。在开发服务器下,端口默认为 5000,但在生产中,端口可能是 80、443 或其他。在开发模式下运行时(或部署所需的任何配置逻辑),您可以编写一个小助手来将端口设置为 5000。

from flask.helpers import get_env

def p(host):
    if get_env() == "development":
        return host + ":5000"

    return host

# p("example.com") -> "example.com:5000"
Run Code Online (Sandbox Code Playgroud)

此示例显示路由到形式为{tree}tree.com和 的任何主机admin.{tree}tree.compinetree.com作为静态主机。

from flask import Flask
app = Flask(__name__, host_matching=True, static_host=p("pinetree.com"))

@app.route("/", host=p("<tree>tree.com"))
def index(tree):
    return f"{tree} tree"
Run Code Online (Sandbox Code Playgroud)

Blueprint尚不接受host选项,因此您需要为每个路由指定主机。您可以使用partial.

from functools import partial
from flask import Blueprint

admin = Blueprint("admin", __name__)
admin_route = partial(admin.route, host=p("admin.<tree>tree.com"))

@admin_route("/")
def index(tree):
    return f"admin for {tree} tree"

app.register_blueprint(admin)
Run Code Online (Sandbox Code Playgroud)

请注意,host可以像路由中的路径一样采用 URL 参数。它将像路径参数一样传递给视图。这允许动态主机和子域。您可以使用@app.url_defaults@app.url_value_preprocessor将其提取到其中,g而不是将其编写为每个视图的参数。

from flask import g

@app.url_value_preprocessor
def extract_tree(endpoint, values):
    g.tree = values.pop("tree")

@app.url_defaults
def inject_tree(endpoint, values):
    values.setdefault("tree", g.tree)

@app.route("/")
def index()
    return f"{g.tree} tree"
Run Code Online (Sandbox Code Playgroud)

在开发过程中,将主机添加到您的主机文件(/etc/hosts在 Unix 上,以便它们路由到 localhost。

127.0.0.1 localhost pinetree.com admin.pinetree.com oaktree.com admin.oaktree.com
Run Code Online (Sandbox Code Playgroud)

并运行:

export FLASK_ENV=development
flask run
Run Code Online (Sandbox Code Playgroud)