【发布时间】: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