How do I make a trailing slash optional with webapp2?

后端 未结 9 815
感情败类
感情败类 2021-02-12 15:30

I\'m using the new webapp2 (now the default webapp in 1.6), and I haven\'t been able to figure out how to make the trailing slash optional in code like this:

web         


        
相关标签:
9条回答
  • 2021-02-12 16:05

    I was looking for a way to make the trailling slash on the root of a PathPrefixRoute block optional.

    If you have, say:

    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),
      ]),
    ])
    

    You will be able to access /admin/, but not /admin.

    Since I couldn't find any better solution, I've added a redirect_to_name to an extra route, like:

    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),
      ]),
    ])
    

    I'm interested in better solutions to this problem.

    Should I go for Stun's solution and simply not use RedirectRoute?

    0 讨论(0)
  • 2021-02-12 16:08

    I came up with a sort of hacky way. I define the following class:

    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
    

    Then I set up my routes like the following:

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

    If you do choose to go this route, you can obviously improve upon it to be more flexible with other types of BaseRoute objects.

    0 讨论(0)
  • 2021-02-12 16:09

    webapp2.Route template is not a regular expressions and your value is being escaped with re.escape. You can use old style rules which provides regular expression templates:

     webapp2.SimpleRoute('^/feed/?$', handler = feed)
    
    0 讨论(0)
  • 2021-02-12 16:12

    To avoid creating duplicate URL:s to the same page, you should use a RedirectRoute with strict_slash set to True to automatically redirect /feed/ to /feed, like this:

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

    Read more at http://webapp2.readthedocs.io/en/latest/api/webapp2_extras/routes.html

    0 讨论(0)
  • 2021-02-12 16:14

    If you don't want to use redirects (and you probably don't), you can override 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
    
    0 讨论(0)
  • 2021-02-12 16:16

    I am not familiar with webapp2, but if the first parameter is a regular expression, try:

    /feed(/)?
    
    0 讨论(0)
提交回复
热议问题