RewriteBase 做啥以及如何使用它?

Posted

技术标签:

【中文标题】RewriteBase 做啥以及如何使用它?【英文标题】:What does RewriteBase do and how to use it?RewriteBase 做什么以及如何使用它? 【发布时间】:2014-02-16 08:07:05 【问题描述】:

我正在尝试学习一些.htaccess 技巧。我遇到了RewriteBase 指令,但无法使其正常工作。

我想知道这个指令具体做什么以及如何使用它。在 *** 和 Apache 文档中有一些关于 RewriteBase 的讨论,但我仍然无法明确回答我的问题。

谁能给我一个简单但有效的例子,RewriteBase 可以使用?

【问题讨论】:

之前在这里问过同样的问题:***.com/questions/704102/…(虽然下面的答案可能是最全面的) How does RewriteBase work in .htaccess的可能重复 【参考方案1】:

RewriteBase 允许您调整mod_rewrite 自动作为RewriteRule 结果前缀的路径。 .htaccess 上下文中的重写是相对于包含该 .htaccess 文件的目录完成的。 RewriteRule 的直接结果仍然与包含 .htaccess 文件的目录相关,但 mod_rewrite 随后会调整此结果,使其相对于文档根目录。 RewriteBase 允许您修改最后一步,允许您提供一个任意的 base 路径,该路径添加到 RewriteRule 的即时结果之前,而不是文档根目录。

对我来说,理解 RewriteBase 指令的关键是当我意识到 mod_rewrite 将 RewriteBase 应用于RewriteRules 的结果,而不是应用于他们的论点。

在.htaccess 文件的上下文中RewriteRule 的正常处理是这样的:

    生成相对于包含 .htaccess 文件的目录的请求路径。例如,如果 URI 是 https://www.example.com/one/two/three 并且 .htaccess 文件的路径是 /doc_root/one/.htaccess,那么生成的路径将是 /two/three。 RewriteRules 然后从上面重写相对路径。 使用 .htaccess 文件的完整文件系统路径为上面生成的重写路径添加前缀 从上面重写路径的开头删除到文档根目录的路径。

此过程会导致相对于文档根目录的重写路径。

当有RewriteBase 指令时,步骤 1,2 和 3 保持不变,只有步骤 4 发生变化。而不是文档根目录,而是删除包含 .htaccess 文件的目录的文件系统路径。然后在前面加上RewriteBase

例子:

请求 - https://example.com/one/two/three/file.txt 文档根目录 - /var/doc_root htaccess 的位置 - /var/doc_root/one/.htaccess RewriteBase - /var/other_location/

如果htaccess文件中没有RewriteBase,则处理为:

    获取相对于 htaccess 的请求路径的一部分 - /two/three/file.txt 重写 - /four/rewritten.txt 添加 .htaccess 文件的路径 - /var/do_root/one/four/rewritten.txt 剥离文档根目录 - one/four/rewritten.txt

使用 .htaccess 文件中的 RewriteBase,将其处理为:

    获取请求路径的一部分相对于 htaccess - /two/three/file.txt 进行重写 - /four/rewritten.txt 预先添加 RewriteBase - /var/other_location/four/rewritten.txt

【讨论】:

/four/rewritten.txt 是从哪里来的?在您的示例中,/fourrewritten.txt 都不是请求或任何规则的一部分,也没有在讨论的任何地方提及。你解释的清晰性突然变得混乱和复杂。另外,我们是否需要很多子目录和备用文件(和子目录)来说明这一点?我非常喜欢“在 rewriteCond 和 rewriteRule 或 ReDirect 之后使用 rewriteBase 的概念——如果它确实总是有效的话。然后添加了一个随机的子目录/文件组,就像一个扳手一样,打破了我的“怀疑”。 @SherylHohman 我相信/four/rewritten.txt 来自步骤 2 中“存在”的“任意重写规则”,即他们说“写”的部分。如,您有/two/three/file.txt,“进行重写”(例如应用您的重写规则),这恰好导致/four/rewritten.txt。希望能解决这个问题。 顺便说一句 @Dom 非常感谢您的出色回答。这确实有助于揭开我多年来一直使用的堆栈级别的神秘面纱,但直到最近才真正需要“工作”太多。现在我明白了。【参考方案2】:

1 行答案是:Rewritebase 设置 rewriterule arg2 的基本路径

字面意思就是这样。 (因此它的工作原理类似于 html basehref、⨕ except it's useful,因为通常在 URL 重写默认基础 [.] 的上下文中不需要。)

如果您有多个重写器,Rewritebase 会使维护变得更容易。 事实上,如果你只使用一行 rewriterule,那么 rewritebase 几乎没有用(因为你可以简单地重写基于 url)。


旁注

当然,您可以完全忽略 rewritebase,只对重写规则使用绝对路径。


相关 a rewritebase undesigned [coincidental] use

【讨论】:

【参考方案3】:

在 htaccess 文件中,mod_rewrite 的工作方式类似于 <Directory><Location> 容器。 RewriteBase 用于提供相对路径基础。

例如,假设您有这样的文件夹结构:

root
 |-- subdir1
 |-- subdir2
       |-- subsubdir

所以你可以访问:

http://example.com/(根) http://example.com/subdir1 (subdir1) http://example.com/subdir2 (subdir2) http://example.com/subdir2/subsubdir(子目录)

通过RewriteRule 发送的URI 是相对于目录的。所以如果你有:

RewriteRule ^(.*)$ - 

在根中,请求为/a/b/c/d,则捕获的URI($1)为a/b/c/d。但是如果规则在subdir2 并且请求是/subdir2/e/f/g 那么捕获的URI 是e/f/g。而如果规则在subsubdir,请求是/subdir2/subsubdir/x/y/z,那么捕获的URI就是x/y/z。规则所在的目录已从 URI 中剥离了该部分。重写基础对此没有影响,这只是每个目录的工作方式。

重写基础所做 的作用是为规则目标中的任何相对路径提供 URL 路径基础(不是文件路径基础)。所以说你有这个规则:

RewriteRule ^foo$ bar.php [L]

bar.php 是相对路径,而不是:

RewriteRule ^foo$ /bar.php [L]

/bar.php 是绝对路径。绝对路径将始终为“根”(在上面的目录结构中)。这意味着如果规则位于“root”、“subdir1”、“subsubdir”等。/bar.php 路径始终映射到http://example.com/bar.php

但是另一个规则,相对路径,它基于规则所在的目录。所以如果

RewriteRule ^foo$ bar.php [L]

在“根”中,您转到http://example.com/foo,您将获得http://example.com/bar.php 的服务。但是,如果该规则在“subdir1”目录中,并且您转到http://example.com/subdir1/foo,您将获得http://example.com/subdir1/bar.php。等等。这有时有效,有时无效,正如文档所说,它应该是相对路径的必需,但大多数时候它似乎有效。除非您正在重定向(使用R 标志,或者因为您的规则目标中有http://host 而隐含)。这意味着这条规则:

RewriteRule ^foo$ bar.php [L,R]

如果它在“subdir2”目录中,并且您转到 http://example.com/subdir2/foo,mod_rewrite 会将相对路径误认为是文件路径而不是 URL 路径,并且由于 R 标志,您将结束被重定向到类似的东西:http://example.com/var/www/localhost/htdocs/subdir1。这显然不是你想要的。

这就是RewriteBase 的用武之地。该指令告诉 mod_rewrite 将什么附加到每个相对路径的开头。所以如果我有:

RewriteBase /blah/
RewriteRule ^foo$ bar.php [L]

并且该规则在“subsubdir”中,转到http://example.com/subdir2/subsubdir/foo 实际上会为我服务http://example.com/blah/bar.php。 “bar.php”被添加到基数的末尾。在实践中,这个例子通常不是你想要的,因为你不能在同一个目录容器或 htaccess 文件中有多个碱基。

在大多数情况下,它是这样使用的:

RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]

这些规则在“subdir1”目录中的位置,并且

RewriteBase /subdir2/subsubdir/
RewriteRule ^foo$ bar.php [L]

将在“subsubdir”目录中。

这部分允许您使您的规则可移植,因此您可以将它们放在任何目录中,并且只需要更改基础而不是一堆规则。例如,如果您有:

RewriteEngine On
RewriteRule ^foo$ /subdir1/bar.php [L]
RewriteRule ^blah1$ /subdir1/blah.php?id=1 [L]
RewriteRule ^blah2$ /subdir1/blah2.php [L]
...

这样转到http://example.com/subdir1/foo 将服务http://example.com/subdir1/bar.php 等。假设您决定将所有这些文件和规则移动到“subsubdir”目录。与其将/subdir1/ 的每个实例都更改为/subdir2/subsubdir/,不如只使用一个基础:

RewriteEngine On
RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]
RewriteRule ^blah1$ blah.php?id=1 [L]
RewriteRule ^blah2$ blah2.php [L]
...

然后当您需要将这些文件和规则移动到另一个目录时,只需更改基础:

RewriteBase /subdir2/subsubdir/

就是这样。

【讨论】:

感谢您的全面回复。现在在我看来,RewriteBase 仅在您想使用 R 标志时才有用。当我在 /subdir1/ 中尝试此操作时:RewriteEngine on|RewriteBase /subdir1/subsubdir/| RewriteRule foo bar.php,对“example.com/subdir1/foo”的请求不会映射到“example.com/subdir1/subsubdir/bar.php”。为什么不呢? @JonLin,那么“捕获 URL”是否有 RewriteBase 等效项?例如,在/subdir1/.htaccess 内部,我有一个命令RewriteRule ^(.*)$ -,当我访问/subdir1/foo 时它会捕获字符串foo。我们如何让它捕获整个/subdir1/foo 而不仅仅是foo %REQUEST_URI 包含整个路径 @JonLin 干得好!感谢您的详细回复,而不仅仅是将我们发送到原始文档。原始文档显然很重要,但对于那些刚接触该主题的人来说,往往缺乏清晰的教程。我现在对 mod_rewrite 规则有了更好的理解,并且可以毫无畏惧地接近原始文档! :) @JonLin OMG 感谢您一次解释了RewriteBase 的所有有用性和用法应该如何解释。 WTF,我读了 Apache 的 mod_rewrite RewriteBase 文档,我猜,三遍,什么都不懂。有时它们往往如此深奥,你不这么认为吗?无论如何,再次感谢,这应该有更多的功劳,绝对应该进入文档

以上是关于RewriteBase 做啥以及如何使用它?的主要内容,如果未能解决你的问题,请参考以下文章

UITextInput 的 Tokenizer,它是做啥用的?

FormControl 是做啥用的?为啥使用它?应该如何使用?

self.addChild 做啥?

为啥 Magento 在产品保存时使整页缓存失效实际上使页面未缓存以及由于未缓存而刷新会做啥

User.findOrCreate 函数是做啥的,啥时候在护照中调用它?

sys.intern() 做啥以及何时使用?