如何使用 webapp2 使尾部斜杠可选?

Posted

技术标签:

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

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

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

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

【问题讨论】:

【参考方案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。

    / /饲料 /喂/ /喂/创建 /feed/create/ /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(/)?

【讨论】:

以上是关于如何使用 webapp2 使尾部斜杠可选?的主要内容,如果未能解决你的问题,请参考以下文章

使用 .htaccess 重定向 404 而不重定向尾部斜杠

使用 RewriteMap 减少重定向

如何在Symfony 4.1中禁用尾部斜杠重定向?

如何在 Rails 应用程序中删除 URL 的尾部斜杠? (在 SEO 视图中)

带有或不带有斜杠的 PHP RegEx

使用 .htaccess 删除尾部斜杠