在子目录中创建 .htaccess 会导致更高级别 .htaccess 中的重写规则停止工作

在子目录中创建 .htaccess 会导致更高级别 .htaccess 中的重写规则停止工作

抱歉,如果之前已经问过/回答过这个问题,但我无法找到这个特定问题的答案。

如果我创建一个带有简单重写规则的 .htaccess 文件,该规则就会起作用。如果我在子目录中创建另一个带有其自身重写配置的 .htaccess 文件,则顶层的主 .htaccess 文件将停止读取。我甚至不需要创建任何规则。只需在子目录中打开重写引擎,更高级别的重写就会停止工作。

我创建了一组包含两个文本文件的子目录:

[root@apachetest html]# cat test/1/test.txt
1

[root@apachetest html]# cat test/2/test.txt
2

还有一个 .htaccess 文件,用于将 test/1/test.txt 重写为 test/2/test.txt

[root@apachetest html]# cat test/.htaccess 
RewriteEngine on
RewriteRule 1/test.txt 2/test.txt [L]

这按预期工作。如果我请求 1/test.txt,我会得到 2/test.txt

[root@apachetest html]# curl localhost/test/1/test.txt
2

但是,如果我在 test/1/ 子目录中创建另一个 .htaccess 文件,那么 test/.htaccess 文件将停止工作。

[root@apachetest html]# echo "RewriteEngine On" > test/1/.htaccess
[root@apachetest html]# curl localhost/test/1/test.txt
1

我已经尝试了 /test/.htaccess 和 /test/1/.htaccess 中的所有 RewriteOptions、Inherit、InheritBefore、InheritDown、InheritDownBefore 和 IgnoreInherit,但是如果 /test/1/.htaccess 中有任何重写配置,我就无法使 /test/.htaccess RewriteRule 正常工作。

我需要能够将 RewriteRules 放在子目录中,而不会影响顶级目录中的 RewriteRules。有人能告诉我我遗漏了什么吗?

答案1

是的,默认情况下,mod_rewrite 指令不会被子配置继承。因此,如果您在子目录.htaccess文件中有 mod_rewrite 指令(即使只是启用或禁用重写引擎),那么父目录/配置中的 mod_rewrite 指令将被完全覆盖 - 它们根本不会被处理。

我已经尝试了所有的 RewriteOptions;Inherit、InheritBefore、InheritDown、InheritDownBefore……

是的,这就是启用 mod_rewrite 继承所需要做的事情。选择哪个选项取决于您希望在何处以及何时继承父/子指令。

然而,“问题”在于 mod_rewrite 指令的“继承”方式。它们是通过将指令有效地复制到相应的配置中来继承的。它们不会在其原始配置的上下文中处理。这会影响相对 URL 路径之类的内容。通常,指令RewriteRule会匹配相对于包含该文件的目录的 URL 路径.htaccess。但是,如果这些指令被“继承”(即有效地复制)到子配置中,那么这些相对 URL 路径将会有所不同,并且规则可能不再匹配。

“继承”指令需要以这样一种方式编写,即它们不依赖于处理它们的目录 - 因此您不一定依赖于RewriteRule 图案在继承指令时目录语境。

因此,用你的例子...

# test/.htaccess 
RewriteEngine on
RewriteRule 1/test.txt 2/test.txt [L]

/test/1并且我们在子目录文件中启用mod_rewrite继承.htaccess

# test/1/.htaccess 
RewriteEngine on

RewriteOptions Inherit

这实际上会导致请求时处理以下内容/test/1/test.txt

# test/1/.htaccess 
RewriteEngine on

RewriteOptions Inherit

# Due to "Inherit" option the inherited directives from the parent config
# are effectively copied in-place after the existing directives...
RewriteRule 1/test.txt 2/test.txt [L]

显然,RewriteRule 图案 1/test.txt文件中的test/1/.htaccess永远不会匹配,因此规则不执行任何操作。(规则需要修改才能匹配test.txt,但代换也需要修改,否则它会将请求重写为/test/1/2/test.txt- 但这并不存在。)

需要修改继承/父级配置中的指令,以避免对父级所在目录的依赖.htaccess。例如:

# test/.htaccess 
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/([^/]+)/1/test\.txt$
RewriteRule (^|/)test\.txt$ /%1/2/test.txt [L]

状况有效地重复了 的测试test.txt,但更具体。你可以制作RewriteRule 图案完全通用,但规则将针对每个请求进行处理。

注意:我捕获了第一个路径段,并%1代换以避免必须对文件所在的目录进行硬编码.htaccess

当 mod_rewrite 用于以下情况时,这种“继承”模式会更加成问题/复杂:目录.htaccess)上下文。 (mod_rewrite 在用于目录上下文。)相对路径问题不是服务器配置/虚拟主机中的指令的问题,因为路径都是相对于根的。

相关内容