【问题标题】:Force a URL-path for mod_rewrite's RewriteRule Substitution强制 mod_rewrite 的 RewriteRule 替换的 URL 路径
【发布时间】:2017-06-09 12:03:51
【问题描述】:

当使用 mod_rewrite 的 RewriteRule 执行重写时,会评估替换并根据替换的根目录是否存在于文件系统上来猜测它是 URL 还是文件系统路径。这是the documentation的相关部分:

网址路径

请注意,mod_rewrite 会通过检查路径的第一段是否存在于文件系统的根目录来尝试猜测您是否指定了文件系统路径或 URL 路径。例如,如果您指定/www/file.html替换 字符串,那么这将被视为URL 路径除非 一个名为www 的目录存在于根或您的文件系统(或者,在 .htaccess 文件中使用重写的情况下,相对于您的文档根目录),在这种情况下,它将被视为文件系统路径。

所以我的问题是,我如何重写一个 URI,其中根目录 存在于文件系统中,但我希望它被视为 URL?

除了指定完整的 URL 之外,还有其他方法吗?同样根据文档:

绝对网址

如果指定了绝对 URL,mod_rewrite 会检查主机名是否与当前主机匹配。如果是这样,则方案和主机名将被删除,并且生成的路径将被视为 URL 路径。否则,将对给定 URL 执行外部重定向。

所以我可以这样绕过它:

RewriteRule ^/example.html$ %{REQUEST_SCHEME}://%{HTTP_HOST}/var/example.html

这对于代码的可读性并不理想。我真的很想能够做到:

RewriteRule ^/example.html$ /var/example.html

/var 存在时,不会将其评估为文件系统路径。似乎没有标志可以强制执行此操作。还有一个风险是稍后会创建匹配路径并违反规则,我想避免这种情况,而不需要太多冗长。

我也知道我可以通过将规则放在 .htaccess 而不是 Apache 配置中来解决这个问题,因此搜索是从文档根目录进行的,如上面引用中所述,但这不是我想要的.

还有其他方法吗?

更新

感谢 Dusan Bajic 的回答,事实证明 [PT] 标志在这里可以提供帮助,正如我错过了文档中的第一个引用的句子中所暗示的那样:

如果您希望将其他 URL 映射指令(例如 Alias)应用于生成的 URL 路径,请使用 [PT] 标志,如下所述。

通过使用[PT] 标志 (docs here),它将导致替换“被视为 URI 而不是 [文件路径]”,这听起来应该回答这个问题,但不幸的是使用[PT] 标志还有其他含义:

  • 这意味着[L],因此不会发生对重写规则的进一步处理。
  • 它会导致 URL 映射再次运行,这正是它的用途,并且在仅仅希望将替换强制解释为 URL 路径时可能不理想。

所以我暂时没有接受这个问题的答案,因为所需的解决方案不会有上述问题。接受的答案将导致替换被视为 URL 路径,就像文件系统中不存在替换的根目录一样,不会以任何其他方式影响处理。

更新 2

我意识到,当 URL 位于文档根目录中时,另一种解决方法是在替换开始时始终添加 %{DOCUMENT_ROOT}。所以它是这样的:

RewriteRule ^/example.html$ %{DOCUMENT_ROOT}/var/example.html

这也可以防止以后处理 URL 的规则起作用,因此它类似于 [PT] 选项,不会导致 URL 映射再次运行。

【问题讨论】:

  • 非常好的问题。我以为RewriteBase 可以解决这个问题,但它只允许在.htaccess 文件中使用。
  • 您可以使用重写条件将%{REQUEST_SCHEME}://%{HTTP_HOST} 存储在一个变量中,然后在您的重写规则中使用%1,但这会添加一个完整的行,因此不确定它是否简化了任何事情。
  • @Capsule 同意,它还可以防止另一个RewriteCond 被使用,该RewriteCond 需要捕获某些内容以在规则中使用。在我看来,确实需要一个标志来强制替换 URL 上下文。它还可以避免每次重写都轮询文件系统。我什至希望看到它是默认值,并且需要该标志来激活文件系统路径,尽管它当然会破坏向后兼容性。
  • 是的,不确定当使用多个时条件捕获如何工作......另一个好问题:-)
  • 我喜欢%{DOCUMENT_ROOT} 方法!

标签: apache mod-rewrite


【解决方案1】:

你忽略了引用段落的最后一句话:

如果您希望应用其他 URL 映射指令(例如 Alias) 到生成的 URL 路径,使用如下所述的 [PT] 标志。

它似乎不适用于您的(非常明智的顺便说一句)问题,但如果您进一步深入了解[PT]

RewriteRule 中的目标(或替换字符串)假定为 默认情况下,文件路径。 [PT] 标志的使用使其成为 而是视为 URI。

例如(如果你打开LogLevel debug rewrite:trace6):

RewriteRule ^/boo$ /opt/mock.png

将记录:

[...] init rewrite engine with requested uri /boo
[...] applying pattern '^/boo$' to uri '/boo'
[...] rewrite '/boo' -> '/opt/mock.png'
[...] local path result: /opt/mock.png
[...] go-ahead with /opt/mock.png [OK]

但是

RewriteRule ^/boo$ /opt/mock.png [PT]

将记录:

[...] init rewrite engine with requested uri /boo
[...] applying pattern '^/boo$' to uri '/boo'
[...] rewrite '/boo' -> '/opt/mock.png'
[...] forcing '/opt/mock.png' to get passed through to next API URI-to-filename handler

【讨论】:

  • 谢谢,这很有用。唯一困扰我的是当规则在主配置中时第二次通过 URL 处理。我将做一些测试,看看是否所有作为 URL 路径处理的替换都会发生这种情况,或者只有在应用 PT 标志时才会发生这种情况。完成后会在这里更新。
  • 我玩过这个,它在一定程度上解决了问题。一个问题是它暗示了[L] 标志,因此如果以后可能需要运行规则,则不能使用它。它不会导致重写规则再次运行,因为我认为它可能来自文档,所以那里没有问题。另一个小烦恼是,它确实会导致重新运行其他 URL 处理,而在正常指定 URL 路径时不会发生这种情况。我真的只是在寻找一种方法来强制将替换解释为 URL 路径,而无需对处理进行任何其他更改。我会用这个新信息更新问题。
猜你喜欢
  • 1970-01-01
  • 2014-03-03
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
相关资源
最近更新 更多