Ich habe ein Präfix, das ich jeder Route hinzufügen möchte. Im Moment füge ich der Route bei jeder Definition eine Konstante hinzu. Gibt es eine Möglichkeit, dies automatisch zu tun?
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"
Die Antwort hängt davon ab, wie Sie diese Anwendung bereitstellen.
Angenommen, Sie führen diese Anwendung in einem WSGI-Container aus (mod_wsgi, uwsgi, gunicorn usw.); Sie müssen tatsächlich mount an diesem Präfix der Anwendung als Unterabschnitt dieses WSGI-Containers (alles, was WSGI spricht, tun) und Ihren APPLICATION_ROOT
config-Wert auf Ihr Präfix setzen:
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/"
Wenn Sie den Wert APPLICATION_ROOT
config festlegen, beschränken Sie einfach das Sitzungscookie von Flask auf dieses URL-Präfix. Alles andere wird automatisch von Flask und den hervorragenden WSGI-Handhabungsfunktionen von Werkzeug bearbeitet.
Wenn Sie sich nicht sicher sind, was der erste Absatz bedeutet, werfen Sie einen Blick auf diese Beispielanwendung, in der Flask installiert ist:
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 __== '__main__':
app.run('localhost', 5000)
Wenn Sie andererseits Ihre Flask-Anwendung im Stammverzeichnis des WSGI-Containers ausführen und Anforderungen an sie weiterleiten (z. B. wenn es sich um eine FastCGI handelt, oder wenn nginx proxy_pass
-Anforderungen für ein Unterprogramm ist). Endpunkt zu Ihrem Standalone-Server uwsgi
gevent
, dann können Sie entweder:
DispatcherMiddleware
von werkzeug
(oder die PrefixMiddleware
von su27s Antwort ), um Ihre Anwendung auf dem eigenständigen WSGI-Server, den Sie verwenden, bereitzustellen. (Siehe Ein Beispiel für das ordnungsgemäße Submounten Ihrer App für den zu verwendenden Code).Sie können Ihre Routen in einen Bauplan setzen:
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"
Dann registrieren Sie den Blueprint mit einem Präfix bei der Anwendung:
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
Sie sollten beachten, dass der APPLICATION_ROOT
NICHT für diesen Zweck ist.
Sie müssen lediglich eine Middleware schreiben, um folgende Änderungen vorzunehmen:
PATH_INFO
, um die vorangestellte URL zu behandeln.SCRIPT_NAME
ändern, um die vorangestellte URL zu generieren.So was:
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()]
Wickeln Sie Ihre App mit der Middleware wie folgt:
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 __== '__main__':
app.run('0.0.0.0', 9010)
Besuchen Sie http://localhost:9010/foo/bar
,
Sie erhalten das richtige Ergebnis: The URL for this page is /foo/bar
Vergessen Sie nicht, die Cookie-Domain festzulegen, wenn Sie dies benötigen.
Diese Lösung wird von Larivact's Gist gegeben. Der APPLICATION_ROOT
ist nicht für diesen Job, obwohl es so aussieht. Es ist wirklich verwirrend.
Dies ist eher eine Python-Antwort als eine Flask/Werkzeug-Antwort. aber es ist einfach und funktioniert.
Wenn Sie wie ich möchten, dass Ihre Anwendungseinstellungen (aus einer .ini
-Datei geladen) auch das Präfix Ihrer Flask-Anwendung enthalten (damit der Wert nicht während der Bereitstellung, sondern zur Laufzeit festgelegt wird), können Sie sich für Folgendes entscheiden:
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
Dies ist wohl etwas hässlich und beruht auf der Tatsache, dass die Flask-Routenfunktion als erstes Positionsargument eine route
erfordert.
Sie können es so verwenden:
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
NB: Es ist nichts wert, dass es möglich ist, eine Variable im Präfix zu verwenden (z. B. indem Sie sie auf /<prefix>
setzen) und dieses Präfix dann in den Funktionen zu verarbeiten, die Sie mit Ihrer @app.route(...)
verzieren. Wenn Sie dies tun, müssen Sie natürlich den Parameter prefix
in Ihren dekorierten Funktionen angeben. Darüber hinaus möchten Sie möglicherweise das gesendete Präfix anhand einiger Regeln überprüfen und einen 404 zurückgeben, wenn die Prüfung fehlschlägt. Um eine benutzerdefinierte 404-Neuimplementierung zu vermeiden, from werkzeug.exceptions import NotFound
und dann raise NotFound()
, falls die Prüfung fehlschlägt.
Ich glaube also, dass eine gültige Antwort darauf lautet: Das Präfix sollte in der tatsächlichen Serveranwendung konfiguriert sein, die Sie verwenden, wenn die Entwicklung abgeschlossen ist. Apache, Nginx usw.
Wenn Sie möchten, dass dies während der Entwicklung funktioniert, während Sie die Flask-App im Debug-Modus ausführen, sehen Sie sich this Gist an.
DispatcherMiddleware
zur Rettung!Ich werde den Code hier für die Nachwelt kopieren:
"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 __== '__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)
Wenn Sie den obigen Code nun als eigenständige Flask-App ausführen, zeigt http://localhost:5000/spam/
Hello, world!
an.
In einem Kommentar zu einer anderen Antwort brachte ich zum Ausdruck, dass ich so etwas tun möchte:
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/
Anwenden von DispatcherMiddleware
auf mein erfundenes Beispiel:
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/
Ein anderer völlig anderer Weg ist mit mountpoints in uwsgi
.
Aus dem Dokument über Hosting mehrerer Apps im selben Prozess ( permalink ).
In Ihrem uwsgi.ini
fügen Sie hinzu
[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
Wenn Sie Ihre Datei nicht main.py
aufrufen, müssen Sie sowohl die mount
als auch die module
ändern.
Ihr main.py
könnte so aussehen:
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
Und eine Nginx-Konfig (wieder zur Vollständigkeit):
server {
listen 80;
server_name example.com
location /foo {
include uwsgi_params;
uwsgi_pass unix:///temp/uwsgi.sock;
}
}
Beim Aufruf von example.com/foo/bar
wird /foo/bar
so angezeigt, wie es von flask url_for('bar')
zurückgegeben wird, da es sich automatisch anpasst. Auf diese Weise funktionieren Ihre Links ohne Präfixprobleme.
Ich brauchte ein ähnliches sogenanntes "Kontextstammverzeichnis". Ich habe es in der conf-Datei unter /etc/httpd/conf.d/ mit WSGIScriptAlias gemacht:
<VirtualHost *:80>
WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py
<Directory /home/<myid>/myapp>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
So kann ich jetzt auf meine App zugreifen: http: // localhost: 5000/myapp
Siehe Handbuch - http://modwsgi.readthedocs.io/de/develop/user-guides/quick-configuration-guide.html
Ich bevorzuge immer die folgende, wenn es darum geht, ein Präfix für die gesamte app
hinzuzufügen:
app = Flask(__name__, root_path='/operators')
Sauber und klar.
Meine Lösung, bei der Flaschen und PHP - Apps nebeneinander existieren Nginx und PHP5.6
KEEP Flask in root und PHP in Unterverzeichnissen
Sudo vi /etc/php/5.6/fpm/php.iniAdd 1 Zeile Cgi.fix_pathinfo = 0
Sudo vi /etc/php/5.6/fpm/pool.d/www.conflisten = /run/php/php5.6-fpm.sock
uwsgi
Sudo vi /etc/nginx/sites-available/defaultUSE NESTED LOCATIONS für PHP und lassen Sie FLASK im Stammverzeichnis bleiben
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;
#}
}
LESEN Sie sorgfältig https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
Wir müssen den Ortsabgleich verstehen. __ (keiner): Wenn keine Modifikatoren vorhanden sind, wird der Ort als Präfixübereinstimmung interpretiert. Dies bedeutet, dass der angegebene Ort mit dem Beginn des Anforderungs-URIs verglichen wird, um eine Übereinstimmung zu ermitteln =: Wenn ein Gleichheitszeichen verwendet wird, wird dieser Block als Übereinstimmung betrachtet, wenn der Anforderungs-URI genau mit dem angegebenen Ort übereinstimmt. ~: Wenn ein Tilde-Modifikator vorhanden ist, wird diese Position als Übereinstimmung zwischen Groß- und Kleinschreibung eines regulären Ausdrucks interpretiert ~ *: Wenn ein Tilde- und Sternchen-Modifikator verwendet wird, wird der Standortblock als Fall interpretiert -insensitive reguläre Ausdrucksübereinstimmung . ^ ~: Wenn ein carat- und tilde-Modifikator vorhanden ist und dieser Block als bester nicht-regulärer Ausdrucksabgleich ausgewählt wird, findet kein regulärer Ausdrucksabgleich statt.
Die Reihenfolge ist aus der Beschreibung von nginx "Standort" wichtig:
Um eine Position zu finden, die einer bestimmten Anforderung entspricht, prüft nginx zunächst die mit den Präfixzeichenfolgen (Präfixpositionen) definierten Positionen. Unter ihnen wird der Ort mit dem längsten übereinstimmenden Präfix ausgewählt und gespeichert. Dann werden reguläre Ausdrücke in der Reihenfolge ihres Aussehens in der Konfigurationsdatei geprüft. Die Suche nach regulären Ausdrücken endet mit der ersten Übereinstimmung und die entsprechende Konfiguration wird verwendet. Wenn keine Übereinstimmung mit einem regulären Ausdruck gefunden wird, wird die zuvor gespeicherte Konfiguration der Präfixposition verwendet.
Es bedeutet:
Erstes =. ("längst passendes Präfix") Dann implizite. (Übereinstimmung mit "längst passendem Präfix") Dann Regex. (erstes Spiel)
from flask import Flask
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
if __== "__main__":
app.run(debug='True', port=4444)
bp = Blueprint('burritos', __name__,
template_folder='templates')
@bp.route('/')
def test():
return "success"