Ответ зависит от того, как вы обслуживаете это приложение.
Подмонтирован внутри другого контейнера WSGI
Предполагая, что вы собираетесь запустить это приложение внутри контейнера WSGI (mod_wsgi, uwsgi, gunicorn и т. Д.); вам нужно на самом деле смонтировать с этим префиксом приложение как часть этого контейнера 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"))
Установка APPLICATION_ROOT
значения конфигурации просто ограничивает cookie сеанса Flask этим префиксом URL. Все остальное будет автоматически обрабатываться за вас с помощью превосходных возможностей обработки WSGI Flask и Werkzeug.
Пример правильного подмонтирования вашего приложения
Если вы не уверены, что означает первый абзац, взгляните на этот пример приложения с установленным внутри него 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)
Проксирование запросов к приложению
Если, с другой стороны, вы будете запускать приложение Flask в корне его контейнера WSGI и передавать ему запросы проксирования (например, если оно выполняется FastCGI, или если nginx выполняет proxy_pass
запросы -ing для субконечной точки на свой автономный uwsgi
/ gevent
сервер, тогда вы можете:
- Используйте Blueprint, как указывает Мигель в своем ответе .
- или использовать
DispatcherMiddleware
из werkzeug
(или PrefixMiddleware
от ответа su27 игровых ) к югу от монтажа приложения в автономном сервере WSGI вы используете. (См. Пример правильного подмонтирования вашего приложения выше, чтобы узнать, какой код использовать).
flask.Flask#create_url_adapter
иwerkzeug.routing.Map#bind_to_environ
, похоже , он должен работать - как ты выполнение кода? (На самом деле приложение должно быть смонтировано на дополнительном пути в среде WSGI,url_for
чтобы возвращать ожидаемое значение.)DispatcherMiddleware
подход, когда запускается только flask. Кажется, не получается заставить это работать, когда вы бежите за Gunicorn.uwsgi -s /tmp/yourapplication.sock --manage-script-name --mount /yourapplication=myapp:app
. подробности см. (документ uwsgi) [ flask.pocoo.org/docs/1.0/deploying/uwsgi/]Вы можете поместить свои маршруты в план:
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')
источник
app.register_blueprint
и между регистрацией его при создании экземпляра объекта Blueprint выше, передаваяurl_prefix='/abc/123
? Спасибо!register_blueprint
вызове дает приложению свободу «монтировать» схему в любом месте или даже монтировать одну и ту же схему несколько раз по разным URL. Если вы поместите префикс в сам план, вы упростите приложение, но у вас будет меньше гибкости.Обратите внимание, что
APPLICATION_ROOT
это НЕ для этой цели.Все, что вам нужно сделать, это написать промежуточное ПО, чтобы внести следующие изменения:
PATH_INFO
для обработки URL-адреса с префиксом.SCRIPT_NAME
чтобы сгенерировать URL-адрес с префиксом.Как это:
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, если вам нужно.
Это решение дает сущность Ларивакта .
APPLICATION_ROOT
Не для этой работы, хотя это выглядит как быть. Это действительно сбивает с толку.источник
APPLICATION_ROOT
не для этой работы» - вот где я ошибся. Я хочуBlueprint
«surl_prefix
параметр иAPPLICATION_ROOT
был объединено по умолчанию, так что я мог быAPPLICATION_ROOT
область видимости URLs для всего приложения иurl_prefix
область действия URLs в пределахAPPLICATION_ROOT
только для индивидуального плана. ВздохAPPLICATION_ROOT
.__call__
method:response = Response('That url is not correct for this application', status=404) return response(environ, start_response)
usingfrom werkzeug.wrappers import BaseResponse as Response
Это скорее ответ 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
Возможно, это несколько хаком и опирается на тот факт , что функция маршрута колба требует
route
в качестве первого позиционного аргумента.Вы можете использовать это так:
app = Flask(__name__) app.route = prefix_route(app.route, '/your_prefix')
NB: ничего не стоит, если можно использовать переменную в префиксе (например, задав ее значение
/<prefix>
), а затем обрабатывать этот префикс в функциях, которые вы украшаете своим@app.route(...)
. Если вы это сделаете, вам, очевидно, придется объявитьprefix
параметр в вашей украшенной функции (ах). Кроме того, вы можете проверить отправленный префикс на соответствие некоторым правилам и вернуть 404, если проверка не удалась. Чтобы избежать повторной реализации 404, пожалуйста,from werkzeug.exceptions import NotFound
а затем,raise NotFound()
если проверка не удалась.источник
Blueprint
. Спасибо, что поделился!Итак, я считаю, что правильный ответ на это: префикс должен быть настроен в реальном серверном приложении, которое вы используете после завершения разработки. Apache, nginx и т. Д.
Однако, если вы хотите, чтобы это работало во время разработки при запуске приложения Flask в отладке, взгляните на эту суть .
Flask спешит
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/
источник
Другой совершенно другой способ - использовать точки монтирования в
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
, вам необходимо изменить как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
как возвращенный flaskurl_for('bar')
, поскольку он адаптируется автоматически. Таким образом, ваши ссылки будут работать без проблем с префиксом.источник
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"
источник
Мне понадобился аналогичный так называемый «контекстный корень». Я сделал это в файле conf в /etc/httpd/conf.d/, используя WSGIScriptAlias:
myapp.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
источник
Мое решение, в котором приложения flask и PHP сосуществуют с nginx и PHP5.6
СОХРАНИТЬ Flask в корне и PHP в подкаталогах
Добавить 1 строку
ИСПОЛЬЗУЙТЕ ВЛОЖЕННЫЕ МЕСТА для 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; #} }
ПРОЧИТАЙТЕ внимательно https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
Нам нужно понимать сопоставление местоположения (нет): если модификаторы отсутствуют, местоположение интерпретируется как совпадение префикса. Это означает, что указанное местоположение будет сопоставлено с началом URI запроса для определения совпадения. =: Если используется знак равенства, этот блок будет считаться совпадающим, если URI запроса точно соответствует указанному местоположению. ~: Если присутствует модификатор тильды, это местоположение будет интерпретировано как совпадение регулярного выражения с учетом регистра. ~ *: Если используются модификаторы тильды и звездочки, блок местоположения будет интерпретироваться как совпадение регулярного выражения без учета регистра. ^ ~: Если присутствует модификатор carat и тильда, и если этот блок выбран как лучшее совпадение нерегулярного выражения, сопоставление регулярного выражения не произойдет.
Порядок важен, исходя из описания "местоположения" nginx:
Чтобы найти местоположение, соответствующее заданному запросу, nginx сначала проверяет местоположения, определенные с помощью строк префикса (местоположения префиксов). Среди них выбирается и запоминается место с самым длинным совпадающим префиксом. Затем проверяются регулярные выражения в порядке их появления в файле конфигурации. Поиск регулярных выражений завершается при первом совпадении, и используется соответствующая конфигурация. Если совпадения с регулярным выражением не найдено, используется ранее запомненная конфигурация расположения префикса.
Это значит:
First =. ("longest matching prefix" match) Then implicit ones. ("longest matching prefix" match) Then regex. (first match)
источник
Для людей, которые все еще борются с этим, первый пример работает, но полный пример здесь, если у вас есть приложение 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, )
источник