我有一个应用程序,它需要多个域指向同一应用程序并显示不同的数据,但是我在所有域中都具有相同的“ admin”子域,该子域还根据域显示不同的数据。
一个例子是:
SERVER_NAME
到目前为止,我发现您需要在Flask配置中编写int...
(域名)才能将子域与Flask一起使用,但是由于我有许多不同类型的树,它们具有唯一的域,并且一直在添加新树,我看不到如何使用该功能。
此外,我已经看到GAE flexible没有多租户,这是我最初想到的将是在GAE上管理多个域的方式。
答案 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.com
和admin.{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