【问题标题】:How do I make a trailing slash optional with webapp2?如何使用 webapp2 使尾部斜杠可选?
【发布时间】:2012-02-08 16:45:01
【问题描述】:

我正在使用新的 webapp2(现在是 1.6 中的默认 webapp),但我无法弄清楚如何在这样的代码中使尾部斜杠成为可选:

webapp.Route('/feed', handler = feed)

我试过/feed/?/feed/*/feed\/*/feed\/?,但都无济于事。

【问题讨论】:

    标签: python google-app-engine webapp2


    【解决方案1】:

    为避免在同一页面创建重复的 URL:s,您应该使用 RedirectRoute 并将 strict_slash 设置为 True 以自动将 /feed/ 重定向到 /feed,如下所示:

    from webapp2_extras.routes import RedirectRoute
    
    route = RedirectRoute('/feed', handler=feed, strict_slash=True)
    

    阅读更多http://webapp2.readthedocs.io/en/latest/api/webapp2_extras/routes.html

    【讨论】:

    • 谢谢。你的意思是说如果我有一百条路由,我也需要一百条重定向路由吗?似乎是一个非常混乱的解决方案。
    • 嗨。不,您将 Routes 替换为 RedirectRoutes,因此您不需要两者。 RedirectRoute 完成了 Route 所做的所有工作,但还添加了“strict_slash”选项以及其他一些重定向功能。查看我在上面发布的链接了解详细信息。
    • 这并不总是一个好主意。如果您的客户端不是网络浏览器(例如,如果您正在为您的网站编写可访问 http 的 api),它可能不会遵循重定向。
    【解决方案2】:

    我正在寻找一种方法来使 PathPrefixRoute 块根部的尾随斜杠成为可选。

    如果你有,说:

    from webapp2_extras.routes import RedirectRoute, PathPrefixRoute
    
    from webapp2 import Route
    
    app = webapp2.WSGIApplication([
      PathPrefixRoute('admin', [
          RedirectRoute('/', handler='DashboardHandler', name='admin-dashboard', strict_slash=True),
          RedirectRoute('/sample-page/', handler='SamplePageHandler', name='sample-page', strict_slash=True),
      ]),
    ])
    

    您将能够访问/admin/,但不能访问/admin

    由于找不到更好的解决方案,我在额外的路由中添加了redirect_to_name,例如:

    from webapp2_extras.routes import RedirectRoute, PathPrefixRoute
    
    from webapp2 import Route
    
    app = webapp2.WSGIApplication([
      Route('admin', handler='DashboardHandler', name='admin-dashboard'),
      PathPrefixRoute('admin', [
          RedirectRoute('/', redirect_to_name='admin-dashboard'),
          RedirectRoute('/sample-page/', handler='SamplePageHandler', name='sample-page', strict_slash=True),
      ]),
    ])
    

    我对这个问题的更好解决方案感兴趣。

    我应该选择 Stun 的解决方案而不使用 RedirectRoute 吗?

    【讨论】:

      【解决方案3】:

      如果您不想使用重定向(而且您可能不会),您可以覆盖 Route.match():

      from webapp2 import Route, _get_route_variables
      import urllib
      from webob import exc
      
      
      class SloppyRoute(Route):
          """
          A route with optional trailing slash.
          """
          def __init__(self, *args, **kwargs):
              super(SloppyRoute, self).__init__(*args, **kwargs)
      
          def match(self, request):
              path = urllib.unquote(request.path)
              match = self.regex.match(path)
              try:
                  if not match and not path.endswith('/'):
                      match = self.regex.match(path + '/')
              except:
                  pass
              if not match or self.schemes and request.scheme not in self.schemes:
                  return None
      
              if self.methods and request.method not in self.methods:
                  # This will be caught by the router, so routes with different
                  # methods can be tried.
                  raise exc.HTTPMethodNotAllowed()
      
              args, kwargs = _get_route_variables(match, self.defaults.copy())
              return self, args, kwargs
      

      【讨论】:

        【解决方案4】:

        我想出了一种 hacky 方式。我定义了以下类:

        class UrlConf(object):
        
            def __init__(self, *args, **kwargs):
                self.confs = []
                for arg in args:
                    if isinstance(arg, webapp2.Route):
                        slash_route = webapp2.Route(arg.template + '/', arg.handler)
                        self.confs += [arg, slash_route]
        
            def __iter__(self):
                for route in self.confs:
                    yield route
        

        然后我设置如下路线:

        MIRROR_URLS = list(UrlConf(
            Route('/path/to/stuff', handler=StuffHandler, name='stuff.page'),
            Route('/path/to/more/stuff', handler= MoreStuffHandler, name='more.stuff.page')
        ))
        

        如果您确实选择了这条路线,您显然可以对其进行改进,使其与其他类型的 BaseRoute 对象更加灵活。

        【讨论】:

          【解决方案5】:

          这对我有用,而且非常简单。它在 webapp2 Route class 中使用模板格式进行 URI 路由。此示例中的尾部斜杠是可选的,没有重定向:

          webapp2.Route('/your_url<:/?>', PageHandler)
          

          人字形之间冒号后的所有内容都被认为是一个正则表达式:&lt;:regex&gt;

          【讨论】:

          • 值得注意的是,您的方法需要额外的参数,这有点糟糕。
          • 无论如何我都会将*args, **kwargs 传递到我的方法中,所以PageHandlerget 将是def get(self, *args, **kwargs)
          【解决方案6】:

          以下是我处理这些路线的方式。

          from webapp2 import Route
          from webapp2_extras.routes import PathPrefixRoute
          import handlers
          
          urls = [
            Route('/foo<:/?>', handlers.Foo),
            Route('/bars', handlers.BarList),
            PathPrefixRoute('/bar', [
              Route('/', handlers.BarList),
              Route('/<bar_id:\w+><:/?>', handlers.Bar),
            ]),
          ]
          ...
          

          请务必注意,您的处理程序需要定义 *args**kwargs 以处理潜在的尾部斜杠,使用此方法将其作为参数发送给它们。

          class Bar(webapp2.RequestHandler):
          
            def get(bar_id, *args, **kwargs):
              # Lookup and render this Bar using bar_id.
              ...
          

          【讨论】:

            【解决方案7】:

            我不喜欢 RedirectRoute 类,因为它会导致不必要的 HTTP 重定向
            根据webapp2 Route class 的文档,这是webapp2.Route with optional leading part 线程中更详细的答案。

            简答

            我的路由模式适用于以下 URL。

            1. /
            2. /饲料
            3. /喂/
            4. /喂/创建
            5. /feed/create/
            6. /feed/edit/{entity_id}
            SITE_URLS = [
                webapp2.Route(r'/', handler=HomePageHandler, name='route-home'),
            
                webapp2.Route(r'/feed/<:(create/?)|edit/><entity_id:(\d*)>',
                    handler=MyFeedHandler,
                    name='route-entity-create-or-edit'),
            
                webapp2.SimpleRoute(r'/feed/?',
                    handler=MyFeedListHandler,
                    name='route-entity-list'),
            ]
            

            希望对你有帮助:-)

            【讨论】:

              【解决方案8】:

              webapp2.Route 模板不是正则表达式,您的值被re.escape 转义。您可以使用提供正则表达式模板的旧式规则:

               webapp2.SimpleRoute('^/feed/?$', handler = feed)
              

              【讨论】:

              • 我想继续使用 webapps 自己的语法,而不是使用正则表达式……从这个意义上说,strict_slash 以最少的代码更改给了我想要的东西。
              【解决方案9】:

              webapp2我不熟悉,但是如果第一个参数是正则表达式,试试:

              /feed(/)?
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2022-01-23
                • 1970-01-01
                • 2020-03-21
                • 2020-08-29
                • 2015-01-16
                • 2013-02-28
                相关资源
                最近更新 更多