답변:
대답은이 애플리케이션을 어떻게 제공하는지에 따라 다릅니다.
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"))
# Will return "The URL for this page is /abc/123/"
APPLICATION_ROOT
구성 값을 설정하면 Flask의 세션 쿠키를 해당 URL 접두사로 제한하기 만하면됩니다. 다른 모든 것은 Flask와 Werkzeug의 뛰어난 WSGI 처리 기능에 의해 자동으로 처리됩니다.
첫 번째 단락이 무엇을 의미하는지 확실하지 않은 경우 내부에 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)
반면에, WSGI 컨테이너의 루트에서 Flask 애플리케이션을 실행하고 이에 대한 요청을 프록시하는 경우 (예 : FastCGI를 사용하는 경우 또는 nginx가 proxy_pass
하위 엔드 포인트에 대한 요청을 -ing하는 경우) 독립 실행 형 uwsgi
/ gevent
서버에 다음 중 하나를 수행 할 수 있습니다.
DispatcherMiddleware
플라스크를 단독으로 실행할 때 접근 방식을 사용하여 작동 합니다. 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"
그런 다음 접두사를 사용하여 애플리케이션에 Blueprint를 등록합니다.
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
app.register_blueprint
위의 블루 프린트 객체를 인스턴스화 할 때 등록하는 것의 차이점을 알고 url_prefix='/abc/123
있습니까? 감사합니다!
register_blueprint
호출에 URL 접두사가 있으면 애플리케이션이 원하는 위치에 Blueprint를 "마운트"하거나 다른 URL에 동일한 Blueprint를 여러 번 마운트 할 수 있다는 것입니다. Blueprint 자체에 접두사를 넣으면 응용 프로그램이 더 쉬워 지지만 유연성이 떨어집니다.
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
필요한 경우 쿠키 도메인을 설정하는 것을 잊지 마십시오.
이 솔루션은 Larivact의 요점에 의해 제공됩니다 . 는 APPLICATION_ROOT
그것을 할 수처럼 보이지만,이 작업이 아니다. 정말 혼란 스럽습니다.
APPLICATION_ROOT
이 일은이 일을위한 것이 아닙니다"-이것이 내가 잘못하고 있었던 곳입니다. 나는 희망 Blueprint
의 url_prefix
매개 변수와 APPLICATION_ROOT
내가 가질 수 그래서, 기본적으로 결합 된 APPLICATION_ROOT
전체 응용 프로그램에 대한 범위 URL 및 url_prefix
내 범위 URL을 APPLICATION_ROOT
단지 개인의 청사진합니다. Sigh
__call__
방법 에서 다음과 같은 방법을 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 답변보다 파이썬 답변에 가깝습니다. 그러나 그것은 간단하고 작동합니다.
저처럼 애플리케이션 설정 ( .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
틀림없이, 이것은 다소 hackish하고 플라스크 경로 기능이 있다는 사실에 의존 필요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 앱을 실행하는 동안 개발 중에이 작업을 수행하려면 이 요점을 살펴보십시오 .
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)
독립 플라스크 응용 프로그램으로 위의 코드를 실행할 때 지금, 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
.
동일한 프로세스에서 여러 앱 호스팅에 대한 문서 ( permalink ).
당신에 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;
}
}
이제 호출 은 자동으로 조정되므로 flask의 반환 된대로 example.com/foo/bar
표시 됩니다. 그러면 링크가 접두사 문제없이 작동합니다./foo/bar
url_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"
비슷한 소위 "컨텍스트 루트"가 필요했습니다. WSGIScriptAlias를 사용하여 /etc/httpd/conf.d/ 아래의 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
플라스크와 PHP 앱이 nginx와 PHP5.6이 공존하는 솔루션
루트에 플라스크 유지 및 하위 디렉토리에 PHP 유지
sudo vi /etc/php/5.6/fpm/php.ini
한 줄 추가
cgi.fix_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에 중첩 된 위치를 사용하고 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가 지정된 위치와 정확히 일치하면이 블록이 일치하는 것으로 간주됩니다. ~ : 물결표 수정자가있는 경우이 위치는 대소 문자를 구분하는 정규식 일치로 해석됩니다. ~ * : 물결표 및 별표 수정자를 사용하면 위치 블록이 대소 문자를 구분하지 않는 정규식 일치로 해석됩니다. ^ ~ : 캐럿 및 물결표 수정자가 있고이 블록이 최상의 비정규 식 일치로 선택되면 정규식 일치가 발생하지 않습니다.
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,
)
flask.Flask#create_url_adapter
및werkzeug.routing.Map#bind_to_environ
그것처럼 보인다 해야 일 - 당신은 어떻게 코드를 실행했다? (응용 프로그램은 실제로위한 WSGI 환경에서 하위 경로에 설치 될 필요가url_for
기대 값을 반환합니다.)