回答:
答えは、このアプリケーションの提供方法によって異なります。
このアプリケーションをWSGIコンテナー(mod_wsgi、uwsgi、gunicornなど)の内部で実行するとします。実際にマウントし、アプリケーションをそのWSGIコンテナーのサブパートとして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のセッションCookieがその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
サブエンドポイントのリクエストを実行している場合)スタンドアロン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"
次に、プレフィックスを使用してアプリケーションにブループリントを登録します。
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
app.register_blueprint
登録することと、上記のBlueprintオブジェクトをインスタンス化するときにそれを登録することの違いを知っていますかurl_prefix='/abc/123
?ありがとうございました!
register_blueprint
呼び出しでURL接頭辞を使用すると、アプリケーションがブループリントを必要な場所に「マウント」したり、異なる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ドメインを設定することを忘れないでください。
この解決策はLarivactの要旨によって与えられます。APPLICATION_ROOT
それがためにのように見えるが、この仕事のためではありません。それは本当に混乱しています。
APPLICATION_ROOT
はこの仕事のためではない」-これは私が間違っていたところです。私はBlueprint
のurl_prefix
パラメーターを希望しAPPLICATION_ROOT
、デフォルトで結合されているAPPLICATION_ROOT
ため、アプリ全体のurl_prefix
スコープURL APPLICATION_ROOT
と、個々のブループリントのスコープURLを含めることができます。ため息
APPLICATION_ROOT
。
__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の回答よりもpythonの回答です。しかし、それはシンプルで機能します。
私のように、(.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
おそらく、これはややハックであり、Flaskルート関数がroute
最初の位置引数としてaを必要とするという事実に依存しています。
次のように使用できます。
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
注意:接頭辞で変数を使用して(たとえば、に設定することにより/<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)
これで、上記のコードをスタンドアロンの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 config(ここでも完全を期します):
server {
listen 80;
server_name example.com
location /foo {
include uwsgi_params;
uwsgi_pass unix:///temp/uwsgi.sock;
}
}
呼び出し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が共存する私のソリューション
ルートにKEEP Flask、サブディレクトリにPHP
sudo vi /etc/php/5.6/fpm/php.ini
1行追加
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;
#}
}
場所の一致を理解する必要があります(なし):修飾子が存在しない場合、場所はプレフィックスの一致として解釈されます。これは、指定された場所がリクエスト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
、期待値を返す必要があります。)