your programing

모든 Flask 경로에 접두사 추가

lovepro 2020. 10. 4. 12:55
반응형

모든 Flask 경로에 접두사 추가


모든 경로에 추가하려는 접두사가 있습니다. 지금은 모든 정의에서 상수를 경로에 추가합니다. 이 작업을 자동으로 수행하는 방법이 있습니까?

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"

대답은이 애플리케이션을 어떻게 제공하는지에 따라 다릅니다.

다른 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"))

# 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서버에 다음 중 하나를 수행 할 수 있습니다.

  • Miguel이 그의 답변 에서 지적했듯이 Blueprint를 사용하십시오 .
  • 또는 사용 DispatcherMiddleware에서 werkzeug(또는 PrefixMiddleware에서 su27의 답변을 에) 서브 마운트 사용하고있는 독립 실행 형 WSGI 서버에서 응용 프로그램을. ( 사용할 코드는 위 의 앱을 올바르게 하위 마운트하는 예를 참조 하세요 .)

경로를 청사진에 넣을 수 있습니다.

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')

APPLICATION_ROOT이 목적을위한 것이 아님을 유의해야합니다 .

다음과 같이 변경하기 위해 미들웨어를 작성하기 만하면됩니다.

  1. PATH_INFO접두사가 붙은 URL을 처리하도록 수정 하십시오.
  2. 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그것을 할 수처럼 보이지만,이 작업이 아니다. 정말 혼란 스럽습니다.


이것은 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>) .NET으로 장식하는 함수에서이 접두사를 처리 하는 것은 가치가 없습니다 @app.route(...). 그렇게한다면 prefix데코 레이팅 된 함수에 매개 변수 를 선언해야합니다 . 또한 제출 된 접두사를 일부 규칙에 대해 확인하고 확인에 실패하면 404를 반환 할 수 있습니다. 404 사용자 정의 재 구현을 방지하기 위해, 제발 from werkzeug.exceptions import NotFound다음 raise NotFound()검사가 실패 할 경우.


따라서 이에 대한 올바른 대답은 개발이 완료 될 때 사용하는 실제 서버 응용 프로그램에서 접두사를 구성해야한다는 것입니다. 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, 당신은 변경해야하는 모두 mountmodule

귀하는 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/barurl_for('bar')


비슷한 소위 "컨텍스트 루트"가 필요했습니다. WSGIScriptAlias를 사용하여 /etc/httpd/conf.d/ 아래의 conf 파일에서 수행했습니다.

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


플라스크와 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를 주의 깊게 읽으십시오.

We need to understand location matching (none): If no modifiers are present, the location is interpreted as a prefix match. This means that the location given will be matched against the beginning of the request URI to determine a match. =: If an equal sign is used, this block will be considered a match if the request URI exactly matches the location given. ~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regular expression match. ~*: If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match. ^~: If a carat and tilde modifier is present, and if this block is selected as the best non-regular expression match, regular expression matching will not take place.

Order is important, from nginx's "location" description:

To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

It means:

First =. ("longest matching prefix" match) Then implicit ones. ("longest matching prefix" match) Then regex. (first match)


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"

참고URL : https://stackoverflow.com/questions/18967441/add-a-prefix-to-all-flask-routes

반응형