关于python:给所有Flask路由添加前缀

您所在的位置:网站首页 communication加前缀 关于python:给所有Flask路由添加前缀

关于python:给所有Flask路由添加前缀

#关于python:给所有Flask路由添加前缀 | 来源: 网络整理| 查看: 265

我有一个要添加到每条路线的前缀。现在,我在每个定义处都向路线添加了一个常量。有没有一种方法可以自动执行此操作?

123456789PREFIX ="/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"

您可以将路线设置为蓝图:

12345678910bp = 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"

然后使用前缀在应用程序中注册蓝图:

12app = Flask(__name__) app.register_blueprint(bp, url_prefix='/abc/123') 相关讨论 嗨,米格尔;您是否知道像下面用app.register_blueprint为蓝图注册url_prefix和通过传递url_prefix=abc123实例化上面的Blueprint对象时注册蓝图的前缀之间的区别?谢谢! 区别在于,在register_blueprint调用中具有URL前缀使应用程序可以自由地"挂载"所需的任何蓝图,甚至可以将同一蓝图多次装载在不同的URL上。如果将前缀放在蓝图本身中,则可以简化应用程序的工作,但灵活性较低。 谢谢!!那很有帮助。我对明显的冗余感到困惑,但是我看到了这两种选择之间的权衡。 实际上,我从未尝试过这样做,但是很可能您可以将蓝图和应用程序中的URL前缀与应用程序前缀fist和蓝图前缀组合在一起。 请注意,在装饰有blueprint.route的函数之后,有必要注册该蓝图。 @Miguel如果我想进一步为已经注册为Blueprint的URL加上前缀,该怎么办?就是我只想在123之后添加api,并且我不想在url_prefix中的123之后附加api 我对该代码的每个"部分"应该去哪里有些困惑?我有一个" app "文件夹,其中的init.py包含了我的app.run代码。我在上面的一个目录中有一个init.py文件,该文件设置了我的记录器,并具有Flask(name)行。然后,我有了一个包含所有路由的单独的route.py文件。我在哪里放置此示例代码的每一行来尝试这种方法? 位置并不重要,Flask不在乎。如果您想使事情保持井井有条,可以在应用程序包内的单独模块中编写蓝图。 但是,这对于静态文件不起作用,如何解决? 您可以在蓝图中定义自己的静态路由。使用send_from_directory()函数实现路由。 您在视图函数(或类)中的重定向也将需要进行调整,以使其包含蓝图名称。例如,您需要使用以下方法来代替return redirect(url_for(index_page)):return redirect(url_for(burritos.index_page)) 不要忘记另外设置app.config[APPLICATION_ROOT] = abc123,否则您的cookie无效,因此无法登录,注销等

答案取决于您如何为该应用程序提供服务。

子安装在另一个WSGI容器中

假定您将在WSGI容器(mod_wsgi,uwsgi,gunicorn等)中运行此应用程序;您实际上需要将该应用程序作为该WSGI容器的子部分挂载在该前缀处(任何讲WSGI的东西都可以使用),并将您的APPLICATION_ROOT配置值设置为您的前缀:

1234567app.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的示例应用程序:

12345678910111213141516171819from 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服务器,则您可以:

正如Miguel在回答中指出的那样,使用蓝图。 或使用werkzeug中的DispatcherMiddleware(或su27的答案中的PrefixMiddleware)将应用程序重新装载到正在使用的独立WSGI服务器中。 (请参见上面的正确重新安装您的应用的示例,以获取要使用的代码)。 相关讨论 @jknupp-查看flask.Flask#create_url_adapter和werkzeug.routing.Map#bind_to_environ看起来应该可以工作-您如何运行代码? (实际上,该应用程序实际上需要安装在WSGI环境中的子路径上,以使url_for返回期望值。) 我精确地运行了您编写的内容,但是添加了app = Flask(name)和app.run(debug = True) @jknupp-这是问题所在-您实际上需要将应用程序安装为大型应用程序的子部分(任何讲WSGI的方法都可以)。我整理了一个示例要点,并更新了我的答案,以使我更清楚地知道,我假设一个子安装的WSGI环境,而不是仅在转发子路径请求的代理后面的独立WSGI环境。 单独运行flask时,使用DispatcherMiddleware方法可以实现此目的。当在Gunicorn后面奔跑时,Cant似乎可以正常工作。 @Justin-您是通过Gunicorn配置运行parent_app还是仅运行app? (您需要将parent_app定位为WSGI应用程序)。 这很有道理,谢谢@SeanVieira。我有一个Flask的子类(用于某些其他自定义),因此可能需要覆盖wsgi_app,或者我可以覆盖add_url_rule,这可能更容易吗? 我相信该子安装示例中有一个错字。在app.wsgi_app = DispatcherMiddleware()调用中将" simple "替换为" run_simple "对我有用。 在uwsgi uwsgi -s tmpyourapplication.sock --manage-script-name --mount yourapplication=myapp:app中安装到子路径的方式。详细信息请参阅(uwsgi文档)[flask.pocoo.org/docs/1.0/deploying/uwsgi/]

您应注意,APPLICATION_ROOT并非用于此目的。

您要做的就是编写中间件来进行以下更改:

修改PATH_INFO以处理带前缀的url。 修改SCRIPT_NAME以生成带前缀的url。

赞:

123456789101112131415class 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()]

使用中间件包装您的应用,如下所示:

1234567891011121314from 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的要旨提供。 APPLICATION_ROOT不适用于此作业,尽管看起来很适合。真令人困惑。

相关讨论 感谢您添加此答案。尝试了此处发布的其他解决方案,但这是唯一对我有用的解决方案。使用wfastcgi.py在IIS上部署的Im " APPLICATION_ROOT不适合此工作"-这就是我要去的地方。我希望Blueprint的url_prefix参数和APPLICATION_ROOT在默认情况下结合在一起,以便我可以为整个应用程序使用APPLICATION_ROOT范围URL,而在APPLICATION_ROOT内的url_prefix范围URL仅用于单个蓝图。叹 有关要使用APPLICATION_ROOT尝试执行的操作的示例,请参见此要点。 如果您使用gunicorn,则已经支持SCRIPT_NAME。将其设置为环境变量或将其作为http标头传递:docs.gunicorn.org/en/stable/faq.html 您可以确认密码吗? TypeError: module() takes at most 2 arguments (3 given) 看起来该类带有对象? 目前的代码对我不起作用。经过研究后,我在__call__方法中的else后面提出了这个问题:response = Response(That url is not correct for this application, status=404) return response(environ, start_response)使用from werkzeug.wrappers import BaseResponse as Response

这比Flask / werkzeug答案更像是python答案;但是它很简单并且可以正常工作。

如果像我一样,希望您的应用程序设置(从.ini文件加载)也包含Flask应用程序的前缀(因此,在部署过程中而不是在运行时设置值),则可以选择以下内容:

12345678910def 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作为第一个位置参数的事实。

您可以像这样使用它:

12app = Flask(__name__) app.route = prefix_route(app.route, '/your_prefix')

NB:在前缀中使用变量是毫无意义的(例如,将其设置为 /

12345678910111213141516171819202122232425262728293031323334353637383940414243444546), and then process this prefix in the functions you decorate with your @app.route(...). If you do so, you obviously have to declare the prefix parameter in your decorated function(s). In addition, you might want to check the submitted prefix against some rules, and return a 404 if the check fails. In order to avoid a 404 custom re-implementation, please from werkzeug.exceptions import NotFound and then raise NotFound() if the check fails. [collapse title=""] 它比使用Blueprint简单且高效。感谢分享! [/collapse] 因此,我相信对此的正确答案是:应该在开发完成时使用的实际服务器应用程序中配置前缀。 Apache,nginx等。 但是,如果您希望在调试过程中运行Flask应用程序时在开发过程中工作,请查看此要点。 抢救Flask的DispatcherMiddleware! 为了后代,我将在此处复制代码: [cc lang="python"]"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!。

在对另一个答案的评论中,我表示希望做这样的事情:

123456789101112from flask import Flask, Blueprint # Let's pretend module_blueprint defines a route, '/record//' 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应用于我的人为示例:

1234567891011121314151617from flask import Flask, Blueprint from flask.serving import run_simple from flask.wsgi import DispatcherMiddleware # Let's pretend module_blueprint defines a route, '/record//' 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/ 相关讨论 "因此,我认为对此的一个有效答案是:应该在开发完成时使用的实际服务器应用程序中配置前缀。Apache,nginx等。"问题出在重定向中。如果您有一个前缀并且没有在Flask中设置它,那么当它重定向而不是转到/ yourprefix / path / to / url时,它只会转到/ path / to / url。有没有一种方法可以在nginx或Apache中设置前缀? 我可能会这样做的方法仅仅是使用诸如puppet或Chef之类的配置管理工具,并在其中设置前缀,然后让该工具将更改传播到需要的配置文件中。我什至不假装我知道我在说Apache或Nginx。由于此问题/答案是特定于python的,因此我建议您将方案作为单独的问题发布。如果您这样做,请随时在此处链接到该问题!

12345678910111213141516from 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" 相关讨论 请考虑添加说明。 我发现在Explorerflask和官方文档中有两个很好的解释

另一种完全不同的方式是使用uwsgi中的安装点。

有关在同一过程中托管多个应用程序的文档(永久链接)。

在您的uwsgi.ini中添加

12345678[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可能看起来像这样:

123456from 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配置(同样为了完整性):

123456789server {   listen 80;   server_name example.com   location /foo {     include uwsgi_params;     uwsgi_pass unix:///temp/uwsgi.sock;   } }

现在调用example.com/foo/bar将显示烧瓶url_for('bar')返回的/foo/bar,因为它会自动适应。这样,您的链接将可以正常工作而不会出现前缀问题。

对于仍在为此苦苦挣扎的人们,第一个示例确实有效,但是如果您的Flask应用不受您的控制,则完整示例在此处:

1234567891011121314151617from 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,     )

flask和PHP应用程序共存的我的解决方案 nginx和PHP5.6

KEEP Flask根目录和PHP子目录

1sudo vi /etc/php/5.6/fpm/php.ini

添加1行

1cgi.fix_pathinfo=0 123456sudo 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使用嵌套位置,并让FLASK保留在根目录中

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778server {     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;     #} }

仔细阅读 https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms

我们需要了解位置匹配 (无):如果不存在修饰符,则该位置将解释为前缀匹配。这意味着给定的位置将与请求URI的开头进行匹配以确定匹配。 =:如果使用等号,则如果请求URI完全匹配给定的位置,则此块将被视为匹配。 ?:如果存在波浪号修饰符,则此位置将被解释为区分大小写的正则表达式匹配。 ?*:如果使用波浪号和星号修饰符,则位置块将被解释为不区分大小写的正则表达式匹配。 ^?:如果存在克拉和波浪号修饰符,并且选择了该块作为最佳非正则表达式匹配,则将不会进行正则表达式匹配。

顺序很重要,来自nginx的"位置"描述:

要查找与给定请求匹配的位置,nginx首先检查使用前缀字符串定义的位置(前缀位置)。其中,选择并记住具有最长匹配前缀的位置。然后按照在配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一个匹配项上终止,并使用相应的配置。如果未找到与正则表达式匹配的内容,则使用前面记住的前缀位置的配置。

表示:

123First =. ("longest matching prefix" match) Then implicit ones. ("longest matching prefix" match) Then regex. (first match)

I needed similar so called"context-root". I did it in conf file under /etc/httpd/conf.d/ using WSGIScriptAlias :

myapp.conf:

123456789     WSGIScriptAlias /myapp /home//myapp/wsgi.py             Order deny,allow         Allow from all    

所以现在我可以以以下方式访问我的应用程序:http:// localhost:5000 / myapp

请参阅指南-http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3