Odpowiedź zależy od tego, jak obsługujesz tę aplikację.
Zamontowany w innym pojemniku WSGI
Zakładając, że zamierzasz uruchomić tę aplikację wewnątrz kontenera WSGI (mod_wsgi, uwsgi, gunicorn itp.); musisz faktycznie zamontować, w tym prefiksie aplikację jako część podrzędną tego kontenera WSGI (wszystko, co mówi WSGI) i ustawić APPLICATION_ROOT
wartość konfiguracyjną na swój prefiks:
app.config["APPLICATION_ROOT"] = "/abc/123"
@app.route("/")
def index():
return "The URL for this page is {}".format(url_for("index"))
Ustawienie APPLICATION_ROOT
wartości config ogranicza plik cookie sesji Flask do tego prefiksu adresu URL. Wszystko inne będzie obsługiwane automatycznie przez doskonałe możliwości obsługi WSGI firmy Flask i Werkzeug.
Przykład prawidłowego montażu aplikacji
Jeśli nie jesteś pewien, co oznacza pierwszy akapit, spójrz na tę przykładową aplikację z zamontowanym w niej Flaskiem:
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)
Przesyłanie żądań do aplikacji
Jeśli, z drugiej strony, będziesz uruchamiać aplikację Flask w katalogu głównym jej kontenera WSGI i przekazywać do niej żądania (na przykład, jeśli jest to FastCGI, lub jeśli nginx proxy_pass
wysyła żądania dla punktu końcowego na swój samodzielny uwsgi
/ gevent
serwer, możesz:
- Użyj schematu, jak wskazuje Miguel w swojej odpowiedzi .
- lub użyj
DispatcherMiddleware
from werkzeug
(lub odpowiedzi PrefixMiddleware
from su27 ), aby zamontować swoją aplikację w autonomicznym serwerze WSGI, którego używasz. (Zobacz przykład prawidłowego montażu aplikacji poniżej, aby uzyskać kod do użycia).
flask.Flask#create_url_adapter
iwerkzeug.routing.Map#bind_to_environ
wygląda na to, że powinno działać - jak uruchomiłeś kod? (W rzeczywistości aplikacja musi być zamontowana na ścieżce podrzędnej w środowisku WSGI,url_for
aby zwrócić oczekiwaną wartość.)DispatcherMiddleware
podejście, gdy działa samodzielnie. Nie wydaje się, żeby to działało, gdy działa za Gunicornem.uwsgi -s /tmp/yourapplication.sock --manage-script-name --mount /yourapplication=myapp:app
. szczegóły patrz (dokument uwsgi) [ flask.pocoo.org/docs/1.0/deploying/uwsgi/]Możesz umieścić swoje trasy w planie:
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"
Następnie rejestrujesz projekt w aplikacji za pomocą prefiksu:
app = Flask(__name__) app.register_blueprint(bp, url_prefix='/abc/123')
źródło
app.register_blueprint
a między rejestracją go podczas tworzenia instancji obiektu Blueprint powyżej, przez przejścieurl_prefix='/abc/123
? Dziękuję Ci!register_blueprint
wywołaniu daje aplikacji swobodę „montowania” planu w dowolnym miejscu, a nawet wielokrotnego montowania tego samego schematu na różnych adresach URL. Jeśli umieścisz prefiks w samym schemacie, ułatwiasz aplikację, ale masz mniejszą elastyczność.Należy pamiętać, że plik
APPLICATION_ROOT
NIE jest do tego celu.Wszystko, co musisz zrobić, to napisać oprogramowanie pośredniczące, aby wprowadzić następujące zmiany:
PATH_INFO
aby obsłużyć prefiksowany adres URL.SCRIPT_NAME
aby wygenerować prefiksowany adres URL.Lubię to:
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()]
Otocz swoją aplikację oprogramowaniem pośredniczącym, na przykład:
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)
Odwiedzić
http://localhost:9010/foo/bar
,Uzyskasz właściwy wynik:
The URL for this page is /foo/bar
I nie zapomnij ustawić domeny cookie, jeśli zajdzie taka potrzeba.
Rozwiązanie to wynika z istoty Larivacta . To
APPLICATION_ROOT
nie jest do tej pracy, chociaż wygląda na to. To naprawdę zagmatwane.źródło
APPLICATION_ROOT
nie jest do tej pracy” - tutaj popełniłem błąd. ŻyczęBlueprint
„surl_prefix
parametr iAPPLICATION_ROOT
łączy się domyślnie, tak że mogę miećAPPLICATION_ROOT
adresy URL zakres całej aplikacji iurl_prefix
URL-e zakresów ciąguAPPLICATION_ROOT
tylko dla indywidualnego planu. WestchnienieAPPLICATION_ROOT
.__call__
metodzie:response = Response('That url is not correct for this application', status=404) return response(environ, start_response)
używającfrom werkzeug.wrappers import BaseResponse as Response
Jest to bardziej odpowiedź Pythona niż odpowiedź Flask / werkzeug; ale to proste i działa.
Jeśli, tak jak ja, chcesz, aby ustawienia aplikacji (ładowane z
.ini
pliku) zawierały również prefiks Twojej aplikacji Flask (a zatem nie ustawiano wartości podczas wdrażania, ale w czasie wykonywania), możesz wybrać następujące opcje: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
Prawdopodobnie jest to nieco hackish i opiera się na fakcie, że funkcja trasa Kolba wymaga
route
jako pierwszego argumentu pozycyjnego.Możesz go używać w ten sposób:
app = Flask(__name__) app.route = prefix_route(app.route, '/your_prefix')
NB: Nic nie warte, że w prefiksie można użyć zmiennej (na przykład ustawiając ją na
/<prefix>
), a następnie przetworzyć ten prefiks w funkcjach, które dekorujesz swoim@app.route(...)
. Jeśli to zrobisz, musisz oczywiście zadeklarowaćprefix
parametr w dekorowanej funkcji (funkcjach). Ponadto możesz chcieć sprawdzić przesłany prefiks pod kątem niektórych reguł i zwrócić 404, jeśli sprawdzenie się nie powiedzie. Aby uniknąć ponownej implementacji niestandardowej 404, prosimy,from werkzeug.exceptions import NotFound
a następnie,raise NotFound()
jeśli sprawdzenie się nie powiedzie.źródło
Blueprint
. Dzięki za udostępnienie!Uważam więc, że prawidłowa odpowiedź na to pytanie brzmi: prefiks powinien być skonfigurowany w rzeczywistej aplikacji serwera, której używasz po zakończeniu programowania. Apache, Nginx itp.
Jeśli jednak chcesz, aby to działało podczas programowania podczas uruchamiania aplikacji Flask w trybie debugowania, spójrz na tę istotę .
Kolby
DispatcherMiddleware
na ratunek!Skopiuję kod tutaj dla potomności:
"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)
Teraz, po uruchomieniu powyższego kodu jako samodzielnej aplikacji Flask,
http://localhost:5000/spam/
wyświetli sięHello, world!
.W komentarzu do innej odpowiedzi wyraziłem, że chciałbym zrobić coś takiego:
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/
Odnosząc się
DispatcherMiddleware
do mojego wymyślonego przykładu: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/
źródło
Innym zupełnie innym sposobem są punkty montowania w
uwsgi
.Z dokumentu o hostowaniu wielu aplikacji w tym samym procesie ( link bezpośredni ).
W twojej
uwsgi.ini
dodasz[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
Jeśli nie wywołasz swojego pliku
main.py
, musisz zmienić zarówno rozszerzenie, jakmount
imodule
Twój
main.py
mógłby wyglądać tak: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
I konfiguracja nginx (ponownie dla kompletności):
server { listen 80; server_name example.com location /foo { include uwsgi_params; uwsgi_pass unix:///temp/uwsgi.sock; } }
Teraz wywołanie
example.com/foo/bar
będzie wyświetlane/foo/bar
jako zwrócone przez kolbyurl_for('bar')
, ponieważ dostosowuje się automatycznie. W ten sposób Twoje linki będą działać bez problemów z prefiksami.źródło
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"
źródło
Potrzebowałem podobnego tak zwanego „kontekstowego korzenia”. Zrobiłem to w pliku konfiguracyjnym w /etc/httpd/conf.d/ używając WSGIScriptAlias:
myapp.conf:
<VirtualHost *:80> WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py <Directory /home/<myid>/myapp> Order deny,allow Allow from all </Directory> </VirtualHost>
Więc teraz mogę uzyskać dostęp do mojej aplikacji jako: http: // localhost: 5000 / myapp
Zobacz przewodnik - http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html
źródło
Moje rozwiązanie, w którym aplikacje flask i PHP współistnieją nginx i PHP5.6
ZACHOWAJ Flask w katalogu głównym, a PHP w podkatalogach
Dodaj 1 linię
UŻYJ LOKALIZACJI ZAGNIEŻDŻONYCH dla PHP i pozwól FLASK pozostać w katalogu głównym
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; #} }
PRZECZYTAJ uważnie https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
Musimy zrozumieć dopasowanie lokalizacji (brak): jeśli nie ma żadnych modyfikatorów, lokalizacja jest interpretowana jako dopasowanie prefiksu. Oznacza to, że podana lokalizacja zostanie dopasowana do początku identyfikatora URI żądania w celu określenia dopasowania. =: Jeśli zostanie użyty znak równości, ten blok zostanie uznany za zgodny, jeśli identyfikator URI żądania dokładnie pasuje do podanej lokalizacji. ~: Jeśli obecny jest modyfikator tyldy, ta lokalizacja zostanie zinterpretowana jako dopasowanie wyrażenia regularnego z uwzględnieniem wielkości liter. ~ *: Jeśli używany jest modyfikator tyldy i gwiazdki, blok lokalizacji zostanie zinterpretowany jako dopasowanie wyrażenia regularnego bez rozróżniania wielkości liter. ^ ~: Jeśli obecny jest modyfikator karata i tyldy, a ten blok zostanie wybrany jako najlepsze dopasowanie inne niż wyrażenie regularne, dopasowanie wyrażenia regularnego nie nastąpi.
Porządek jest ważny, z opisu „lokalizacji” nginx:
Aby znaleźć lokalizację pasującą do danego żądania, nginx najpierw sprawdza lokalizacje zdefiniowane przy użyciu ciągów prefiksów (lokalizacji prefiksów). Wśród nich lokalizacja z najdłuższym pasującym prefiksem jest wybierana i zapamiętywana. Następnie sprawdzane są wyrażenia regularne, w kolejności ich występowania w pliku konfiguracyjnym. Wyszukiwanie wyrażeń regularnych kończy się przy pierwszym dopasowaniu i używana jest odpowiednia konfiguracja. Jeśli nie zostanie znalezione dopasowanie do wyrażenia regularnego, używana jest konfiguracja zapamiętanej wcześniej lokalizacji prefiksu.
To znaczy:
First =. ("longest matching prefix" match) Then implicit ones. ("longest matching prefix" match) Then regex. (first match)
źródło
Dla osób, które wciąż mają z tym problemy, pierwszy przykład działa, ale pełny przykład znajduje się tutaj, jeśli masz aplikację Flask, nad którą nie masz kontroli:
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, )
źródło