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

时间:2018-08-16 19:01:52

标签: python google-app-engine flask

我有一个应用程序,它需要多个域指向同一应用程序并显示不同的数据,但是我在所有域中都具有相同的“ admin”子域,该子域还根据域显示不同的数据。

一个例子是:

SERVER_NAME

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

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

2 个答案:

答案 0 :(得分:2)

Subdomain matching, explained in another answer,如果您有一个基本域和多个子域,则应使用。因为Flask可以推断出与其匹配的URL有关的更多信息,所以更为简单。

但是,如果您有多个基本域,则应改用host matching。您必须在app对象上设置host_matching=True,并设置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"

此示例显示了路由到{tree}tree.comadmin.{tree}tree.com形式的任何主机,其中pinetree.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"

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)

请注意,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"

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

127.0.0.1 localhost pinetree.com admin.pinetree.com oaktree.com admin.oaktree.com

并运行:

export FLASK_ENV=development
flask run

答案 1 :(得分:0)

这是我几年前制作的一个小型图书馆,可能会有所帮助:https://github.com/wiota/landlord(此模式通常称为“多租户”或“多租户应用”,因此得名)。

当您想要使用主机名(似乎正是您所要查找的)来响应具有不同内容的实质上相同的应用程序时,这很有用。

简而言之,将这样的现有应用程序包装在app.py中:

from flask import Flask
from landlord import Landlord
from your_app import create_app

if __name__ == '__main__' :
    app = Flask(__name__)
    app.wsgi_app = Landlord(create_app)
    app.run()

然后在子应用程序的__init__.py中,create_app函数将获得一个hostname参数,该参数允许您执行每个主机的逻辑:

from flask import Flask

def create_app(hostname):
    app = Flask(__name__)
    app.config['HOST'] = hostname

    @app.route('/')
    def root():
        return "Currently running on host: %s" % (app.config['HOST'])

    return app