2

私はBottle.pyサービスを介して大量のファイルをサーバーする既存のPythonアプリケーションを持っています。

次に、サーバーが反応するパスを変更する必要があります。
明らかな方法は、@routeステートメントを変更し、各ルートに新しいパスを追加することです。

しかし、私は古いパスがしばらくの間機能し続けるべきであるという制約を受けました。サーバーも古い要求に応答する必要があるため、古いパスと新しいパスで1回取得するには、各ルートステートメントを複製する必要があります。

したがって、簡単に言うと、次からの変更になります。

@route('/somefile')
def doSomeStuff():

に:

@route('/somefile')
@route('/newpath/somefile')
def doSomeStuff():

しかし、ルートがたくさんあり、すべてのコードをいじりたくないので、ルーティングが発生する前にリクエストを処理するためのエレガントな方法を探しています。

ルーティングプロセスに接続する方法はありますか?


私の現在のアプローチはブラウザに301を提供することですが、リクエストの数が増え、ユーザーのURLが変更されるため、このソリューションは好きではありません。

#Serve a 301 (hope the browsers remember it for a session at least)
@route('/newpath<path:path>')
def redirectNewToOld(path):
    if len(path) == 0:                         #Catch the lazy typers
        path = '/'
    redirect(path, code=301)
4

2 に答える 2

3

2つのことが思い浮かびますが、Webアプリの前にnginxを配置するほど優れているものはありません。1つ目は、ミドルウェアクラスを使用して書き換えるPATH_INFOことです。そのためのWSGIRewriteがありますが、一般的な考え方は次のとおりです。

from bottle import route, run, app

@route('/oldpath/somefile')
def index(): return 'Hello'

class RewriteMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, env, res):
        path = env['PATH_INFO']
        if path.startswith('/newpath'):
            env['PATH_INFO'] = path.replace('/newpath', '/oldpath', 1)

        return self.app(env, res)

app = RewriteMiddleware(app())
run(app)

または、明示的なルーティングを使用することもできますが、これによりボトルの魅力が失われます。

from bottle import run, route

def index(): return 'Hello'

routes = (
    ('/oldpath/hello', 'GET', index),
    ('/oldpath/world', ['GET', 'POST'], index),
    )

def setup_routing():
    for path, method, handler in routes:
        if path.startswith('/oldpath'):
            newpath = path.replace('/oldpath', '/newpath', 1)
            route(newpath, method, handler)

        route(path, method, handler)

setup_routing()
run()

質問を読み直した後、2番目のオプションは、多くのコードを変更する必要があるため、失敗したようです。ただし、既存のすべてのルートを繰り返し処理して、新しいルートを追加することはできます。

for route in bottle.default_app[0].routes:
    if route.rule.startswith(...):
        bottle.route(..., route.call)
于 2012-10-26T10:31:51.967 に答える
0

さて、私はボトル用に独自のmod_rewriteを作成しました。
コードはGitHubにもあります

変更点:

(2012年10月29日、本日作成されたフォークに基づく)

@Lines 754ffでは、次の1つが追加されていますclass Bottle(object):

def _handle(self, environ):
    try:
        environ['bottle.app'] = self
+       url_rewrite.apply(environ)    #Added mod_rewrite
        request.bind(environ)
        response.bind()
        route, args = self.router.match(environ)
        environ['route.handle'] = route
        environ['bottle.route'] = route
        environ['route.url_args'] = args
        return route.call(**args)

下部に追加

###############################################################################
# Nippey #### 29.10.2012 #### mod_rewrite #####################################
###############################################################################
# This modification to bottly.py allows the application of rewrite rules to 
# requests _before_ they are processed by the routing system

class UrlRewriteException(BottleException):
    """ This is a base class for all rewrite related exceptions """

class UrlRewrite():
    """ This class processes every URL before is is passed to the routing system 
    In case one of the included rewrite rules matches the URL, the URL will be modified.
    New rules can be added via the .addRule(str, str, bool) method.
    For each requested URL, the method apply will be called with the environ variable as parameter.
    """
    
    def __init__(self):
        """ Initiates the rules variable """
        print("UrlRewrite init.")
        self.rules = []
    
    def addRule(self, match, replace, final=False):
        """ Add a new rule.
        match:   Regular expression to search for. Can be a string or a compiled regular expression
        replace: Replacement string. May use backreferences.
        final:   If a rule with <final=True> matches the URL, the evaluation will be stopped afterwards
        """
        print("UrlRewrite addRule.")
        if type(match) is not str and type(replace) is not str:
            raise UrlRewriteException
        pattern = re.compile(match)
        self.rules.append({'pattern':pattern, 'repl':replace, 'final':bool(final)})
    
    def apply(self, environ):
        """ Test a URL for a match of one of the saved rules and rewrite it if required
        environ: Environmental variable created by bottle on each request. Contains the PATH_INFO 
                 information, modification will happen with the reference to this variable.
        returns: Returns true if a rewrite has been executed. Not used by the main program (yet)
                 Original path will still be available as PATH_INFO_ORIGINAL in the environ variable
        """
        print("UrlRewrite apply.")
        rewritten = False
        url = environ['PATH_INFO']
        for rule in self.rules:             #Try to alppy each of the rules
            (url, noSubs) = rule['pattern'].subn(rule['repl'], url)
            if noSubs > 0:
                rewritten = True
                if rule['final']:
                    break
        if rewritten:
            environ['PATH_INFO_ORIGINAL'] = environ['PATH_INFO']
            environ['PATH_INFO'] = url
            return True
        return False

    """ EXAMPLES:
    
    #Backreferences may be used by the replacement string
    from bottle import url_rewrite
    url_rewrite.addRule("^/he(l*)o", r"/by\1e", False)
    #Input:  "/hello/test_hello" 
    #Output: "/bye/test_hello"
    
    #All matching occurences will be replaced
    from bottle import url_rewrite
    url_rewrite.addRule("hello", "bye", False)
    #Input:  "/hello/test_hello" 
    #Output: "/bye/test_bye"
    
    #Rules will be applied in successive order
    from bottle import url_rewrite
    url_rewrite.addRule("hello", "hi", False)
    url_rewrite.addRule("hi", "bye", False)
    #Input:  "/hello/test_hello" 
    #Output: "/bye/test_bye"
    
    #Rules won't be re-applied from the start if one rule matches
    from bottle import url_rewrite
    url_rewrite.addRule("hi", "bye", False)
    url_rewrite.addRule("hello", "hi", False)
    #Input:  "/hello/test_hello" 
    #Output: "/hi/test_hi"
    
    #After applying a rule with <final> set to True, the evaluation will be finished
    from bottle import url_rewrite
    url_rewrite.addRule("hello", "hi", True)
    url_rewrite.addRule("hi", "bye", False)
    #Input:  "/hello/test_hello" 
    #Output: "/hi/test_hi"
    """
# END class UrlRewrite

url_rewrite = UrlRewrite()
# END ## mod_rewrite ## Nippey

プルリクエストを送信しましたが、プルされない場合に備えてここにあります。;)

于 2012-10-29T07:05:01.387 に答える