Python 为所有管线添加前缀
我有一个前缀,我想添加到每个路由。现在,我在每个定义处为路由添加一个常量。有没有一种方法可以自动做到这一点Python 为所有管线添加前缀,python,routes,flask,Python,Routes,Flask,我有一个前缀,我想添加到每个路由。现在,我在每个定义处为路由添加一个常量。有没有一种方法可以自动做到这一点 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 burri
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"
答案取决于您如何为该应用程序提供服务 子组件安装在另一个WSGI容器内 假设您将在WSGI容器(mod_WSGI、uwsgi、gunicorn等)中运行此应用程序;您需要在该前缀处将应用程序作为WSGI容器的一个子部分实际装载(任何说WSGI的都可以),并将配置值设置为前缀:
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/"
设置配置值只是将Flask的会话cookie限制为该URL前缀。Flask和Werkzeug出色的WSGI处理能力将为您自动处理所有其他内容
正确安装应用程序的示例
如果您不确定第一段的意思,请查看安装有烧瓶的示例应用程序:
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'd to,或者如果nginx是proxy\u pass
,将子端点的请求代理给您的独立uwsgi
/gevent
服务器,则您可以:
- 使用一个蓝图,正如米格尔在书中指出的那样
- 或者使用
中的werkzeug
(或DispatcherMiddleware
from)在您使用的独立WSGI服务器中分载您的应用程序。(请参阅上面正确分载您的应用程序以使用代码的示例)PrefixMiddleware
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')
您应该注意,
应用程序\u ROOT
并非用于此目的
您所要做的就是编写一个中间件来进行以下更改:
PATH\u INFO
以处理带前缀的urlSCRIPT\u NAME
以生成带前缀的urlclass 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)
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/
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
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
访问http://localhost:9010/foo/bar
您将得到正确的结果:此页面的URL是/foo/bar
如果需要,不要忘记设置cookie域
这个解决方案是由给出的。
应用程序\u ROOT
不适合这个工作,尽管它看起来像是。它确实令人困惑。因此,我认为一个有效的答案是:前缀应该在开发完成时使用的实际服务器应用程序中配置。Apache、nginx等等
但是,如果您希望在开发过程中在调试中运行Flask应用程序时使用此功能,请参阅
Flask的调度终端软件去救援!
我将把代码复制到这里供子孙后代使用:
"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/
将显示你好,世界!
在对另一个答案的评论中,我表示我希望这样做:
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)
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/
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
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
这更像是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函数需要一个route
作为第一个位置参数这一事实
您可以这样使用它:
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)
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/
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
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
注意:在前缀中使用变量(例如,将其设置为/
),然后在您用@app.route(…)
修饰的函数中处理此前缀,这是毫无意义的。如果这样做,您显然必须在修饰的函数中声明prefix
参数。此外,您可能希望根据某些规则检查提交的前缀,如果检查失败,则返回404。为了避免404自定义重新实现,请从werkzeug导入。异常导入NotFound
,如果检查失败,则导入提升NotFound()
。我需要类似的所谓“上下文根目录”.I使用WSGIScriptAlias在/etc/httpd/conf.d/下的conf文件中执行此操作:
myapp.conf:
WSGIScriptAlias/myapp/home//myapp/wsgi.py
命令拒绝,允许
通融
现在我可以通过以下方式访问我的应用程序:
参见指南-另一种完全不同的方式是在uwsgi
中使用挂载点
从文档中获取关于()的信息
在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
,则需要同时更改装载
和模块
您的main.py
可能如下所示:
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)
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/
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
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配置(同样为了完整性):
现在调用example.com/foo/bar
将显示flask的url\u为('bar')
返回的/foo/bar
,因为它会自动调整。这样你的链接将不会出现前缀问题。我的解决方案,其中flask和PHP应用程序共存
nginx和PHP5.6
将Flask保存在root目录中,将PHP保存在子目录中
sudo vi/etc/php/5.6/fpm/php.ini
添加1行
cgi.fix\u pathinfo=0
sudo vi/etc/php/5.6/fpm/pool.d/www.conf
listen=/run/php/php5.6-fpm.sock
uwsgi
sudo vi/etc/nginx/sites available/default
对PHP使用嵌套位置,并让烧瓶保留在根中
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的开头匹配,以确定匹配。
=:I