我有一个我想要添加到每个路线的前缀。现在我在每个定义中为路径添加一个常量。有没有办法自动执行此操作?
PREFIX = "/abc/123"
@app.route(PREFIX + "/")
def index_page():
return "This is a website about burritos"
@app.route(PREFIX + "/about")
def about_page():
return "This is a website about burritos"
答案 0 :(得分:76)
您可以将路线放在蓝图中:
bp = Blueprint('burritos', __name__,
template_folder='templates')
@bp.route("/")
def index_page():
return "This is a website about burritos"
@bp.route("/about")
def about_page():
return "This is a website about burritos"
然后使用前缀
在应用程序中注册蓝图app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
答案 1 :(得分:60)
答案取决于您如何为此应用程序提供服务。
假设您要在WSGI容器(mod_wsgi,uwsgi,gunicorn等)中运行此应用程序;你需要实际 mount,在该前缀将该应用程序作为该WSGI容器的子部分(任何能说WSGI的东西)并将APPLICATION_ROOT
配置值设置为您的前缀:
app.config["APPLICATION_ROOT"] = "/abc/123"
@app.route("/")
def index():
return "The URL for this page is {}".format(url_for("index"))
# Will return "The URL for this page is /abc/123/"
设置APPLICATION_ROOT
配置值只是将Flask的会话cookie限制为该URL前缀。 Flask和Werkzeug出色的WSGI处理能力将为您自动处理其他所有内容。
如果您不确定第一段的含义,请查看此示例应用程序并在其中安装Flask:
from flask import Flask, url_for
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/abc/123'
@app.route('/')
def index():
return 'The URL for this page is {}'.format(url_for('index'))
def simple(env, resp):
resp(b'200 OK', [(b'Content-Type', b'text/plain')])
return [b'Hello WSGI World']
app.wsgi_app = DispatcherMiddleware(simple, {'/abc/123': app.wsgi_app})
if __name__ == '__main__':
app.run('localhost', 5000)
另一方面,如果您将在其WSGI容器的根目录下运行Flask应用程序并代理对它的请求(例如,如果它是FastCGI,或者nginx是proxy_pass
-ing请求您的独立uwsgi
/ gevent
服务器的子端点,然后您可以:
DispatcherMiddleware
中的werkzeug
(或su27's answer中的PrefixMiddleware
)将您的应用程序分装到独立版中您正在使用的WSGI服务器。 (有关要使用的代码,请参阅上面正确子安装应用的示例)。答案 2 :(得分:32)
您应该注意APPLICATION_ROOT
不是出于此目的。
您所要做的就是编写一个中间件来进行以下更改:
PATH_INFO
以处理带前缀的网址。SCRIPT_NAME
以生成带前缀的网址。像这样:
class PrefixMiddleware(object):
def __init__(self, app, prefix=''):
self.app = app
self.prefix = prefix
def __call__(self, environ, start_response):
if environ['PATH_INFO'].startswith(self.prefix):
environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
environ['SCRIPT_NAME'] = self.prefix
return self.app(environ, start_response)
else:
start_response('404', [('Content-Type', 'text/plain')])
return ["This url does not belong to the app.".encode()]
用中间件包装你的应用程序,如下所示:
from flask import Flask, url_for
app = Flask(__name__)
app.debug = True
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo')
@app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
if __name__ == '__main__':
app.run('0.0.0.0', 9010)
访问http://localhost:9010/foo/bar
,
您将获得正确的结果:The URL for this page is /foo/bar
如果需要,请不要忘记设置cookie域。
此解决方案由Larivact's gist给出。 APPLICATION_ROOT
不适合这项工作,尽管看起来很像。这真的令人困惑。
答案 3 :(得分:8)
这更像是一个python答案而不是Flask / werkzeug答案;但它很简单而且很有效。
如果像我一样,您希望您的应用程序设置(从.ini
文件加载)也包含Flask应用程序的前缀(因此,不要在部署期间设置值,而是在运行时),您可以选择以下内容:
def prefix_route(route_function, prefix='', mask='{0}{1}'):
'''
Defines a new route function with a prefix.
The mask argument is a `format string` formatted with, in that order:
prefix, route
'''
def newroute(route, *args, **kwargs):
'''New function to prefix the route'''
return route_function(mask.format(prefix, route), *args, **kwargs)
return newroute
可以说,这有点过时了,并且依赖于Flask路线函数需要 route
作为第一个位置参数。
你可以像这样使用它:
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
注意:在前缀中使用变量是可能的(例如,通过将其设置为/<prefix>
),然后在您使用{装饰的函数中处理此前缀,这是值得的。 {1}}。如果这样做,您显然必须在装饰函数中声明@app.route(...)
参数。此外,您可能希望根据某些规则检查提交的前缀,如果检查失败则返回404。为了避免404自定义重新实施,如果检查失败,请prefix
然后from werkzeug.exceptions import NotFound
。
答案 4 :(得分:3)
因此,我认为对此的有效答案是:应在开发完成时使用的实际服务器应用程序中配置前缀。 Apache,nginx等
但是,如果您希望在调试期间运行Flask应用程序时在开发期间使用此功能,请查看this gist。
DispatcherMiddleware
救援!我会在这里复制代码以供后代使用:
"Serve a Flask app on a sub-url during localhost development."
from flask import Flask
APPLICATION_ROOT = '/spam'
app = Flask(__name__)
app.config.from_object(__name__) # I think this adds APPLICATION_ROOT
# to the config - I'm not exactly sure how!
# alternatively:
# app.config['APPLICATION_ROOT'] = APPLICATION_ROOT
@app.route('/')
def index():
return 'Hello, world!'
if __name__ == '__main__':
# Relevant documents:
# http://werkzeug.pocoo.org/docs/middlewares/
# http://flask.pocoo.org/docs/patterns/appdispatch/
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
app.config['DEBUG'] = True
# Load a dummy app at the root URL to give 404 errors.
# Serve app at APPLICATION_ROOT for localhost development.
application = DispatcherMiddleware(Flask('dummy_app'), {
app.config['APPLICATION_ROOT']: app,
})
run_simple('localhost', 5000, application, use_reloader=True)
现在,当将上述代码作为独立的Flask应用运行时,http://localhost:5000/spam/
将显示Hello, world!
。
在对另一个答案的评论中,我表示我希望做这样的事情:
from flask import Flask, Blueprint
# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
app.run()
# I now would like to be able to get to my route via this url:
# http://host:8080/api/some_submodule/record/1/
将DispatcherMiddleware
应用于我的设计示例:
from flask import Flask, Blueprint
from flask.serving import run_simple
from flask.wsgi import DispatcherMiddleware
# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
application = DispatcherMiddleware(Flask('dummy_app'), {
app.config['APPLICATION_ROOT']: app
})
run_simple('localhost', 5000, application, use_reloader=True)
# Now, this url works!
# http://host:8080/api/some_submodule/record/1/
答案 5 :(得分:2)
另一种完全不同的方式是使用uwsgi
中的挂载点。
来自Hosting multiple apps in the same process(permalink)的文档。
在uwsgi.ini
添加
[uwsgi]
mount = /foo=main.py
manage-script-name = true
# also stuff which is not relevant for this, but included for completeness sake:
module = main
callable = app
socket = /tmp/uwsgi.sock
如果您没有调用文件main.py
,则需要同时更改mount
和module
您的main.py
可能如下所示:
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
# end def
和nginx配置(再次完整性):
server {
listen 80;
server_name example.com
location /foo {
include uwsgi_params;
uwsgi_pass unix:///temp/uwsgi.sock;
}
}
现在调用example.com/foo/bar
会显示/foo/bar
,因为它会自动适应。url_for('bar')
。这样你的链接就可以在没有前缀问题的情况下工作。
答案 6 :(得分:1)
我需要类似的所谓&#34; context-root&#34;。我使用WSGIScriptAlias在/etc/httpd/conf.d/下的conf文件中完成了它:
<VirtualHost *:80>
WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py
<Directory /home/<myid>/myapp>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
现在我可以访问我的应用:http://localhost:5000/myapp
请参阅指南 - http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html
答案 7 :(得分:1)
在向整个app
添加前缀时,我总是喜欢使用以下内容:
app = Flask(__name__, root_path='/operators')
清洁并清除。
答案 8 :(得分:1)
flask和PHP应用程序共存的我的解决方案 nginx和PHP5.6
在根目录下保留烧瓶,在子目录中保留PHP
sudo vi /etc/php/5.6/fpm/php.ini 加1行 cgi.fix_pathinfo = 0
sudo vi /etc/php/5.6/fpm/pool.d/www.conf 听= /run/php/php5.6-fpm.sock
uwsgi
sudo vi / etc / nginx / sites-available / default 在PHP中使用嵌套位置,并让FLASK保留在根目录中
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.php index.nginx-debian.html;
server_name _;
# Serve a static file (ex. favico) outside static dir.
location = /favico.ico {
root /var/www/html/favico.ico;
}
# Proxying connections to application servers
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:5000;
}
location /pcdp {
location ~* \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
location /phpmyadmin {
location ~* \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php7.0-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php7.0-fpm:
# fastcgi_pass unix:/run/php/php7.0-fpm.sock;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
我们需要了解位置匹配 (无):如果不存在修饰符,则该位置将解释为前缀匹配。这意味着给定的位置将与请求URI的开头进行匹配以确定匹配。 =:如果使用等号,则如果请求URI完全匹配给定的位置,则此块将被视为匹配。 〜:如果存在波浪号修饰符,则此位置将被解释为区分大小写的正则表达式匹配。 〜*:如果使用波浪号和星号修饰符,则位置块将被解释为不区分大小写的正则表达式匹配。 ^〜:如果存在克拉和波浪号修饰符,并且选择此块作为最佳非正则表达式匹配项,则不会进行正则表达式匹配。
根据nginx的“位置”说明,顺序很重要:
要查找与给定请求匹配的位置,nginx首先检查使用前缀字符串定义的位置(前缀位置)。其中,将选择并记住具有最长匹配前缀的位置。然后按照在配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一个匹配项上终止,并使用相应的配置。如果未找到与正则表达式匹配的内容,则使用之前记住的前缀位置的配置。
这意味着:
第一个=。 (“最长匹配前缀”匹配) 然后是隐式的。 (“最长匹配前缀”匹配) 然后是正则表达式。 (第一场比赛)
答案 9 :(得分:1)
对于仍在为此奋斗的人们,第一个示例确实有效,但是如果您的Flask应用不受您的控制,则完整示例在此处:
from os import getenv
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.serving import run_simple
from custom_app import app
application = DispatcherMiddleware(
app, {getenv("REBROW_BASEURL", "/rebrow"): app}
)
if __name__ == "__main__":
run_simple(
"0.0.0.0",
int(getenv("REBROW_PORT", "5001")),
application,
use_debugger=False,
threaded=True,
)
答案 10 :(得分:0)
from flask import Flask
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
if __name__ == "__main__":
app.run(debug='True', port=4444)
bp = Blueprint('burritos', __name__,
template_folder='templates')
@bp.route('/')
def test():
return "success"
答案 11 :(得分:0)
我认为 su27 的回答是正确的。我正在使用 gevent,这是我的代码,它工作正常:
from gevent import pywsgi
# your flask code ...
# app = Flask(__name__)
if __name__ == "__main__":
class MyHandler(pywsgi.WSGIHandler):
def get_environ(self):
prefix = "/your_prefix"
env = super().get_environ()
if env['PATH_INFO'].startswith(prefix):
env['PATH_INFO'] = env['PATH_INFO'][len(prefix):]
env['SCRIPT_NAME'] = prefix
return env
server = pywsgi.WSGIServer(('', 8080), app, handler_class=MyHandler)
server.serve_forever()
答案 12 :(得分:0)
在flask blueprint中,我们可以使用-
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/prefix-text'
任何想要在 flask-restful 中做的事情都可以使用 -
app = Flask(__name__)
api = Api(app, prefix='/pefix-text')
现在,您的所有路由都将以 /prefix-text
为前缀。只要确保在您可能只使用过 url_for('link')
的地方使用 /link
。