我一直在为客户想出一些重定向,他们需要在 domain.com 上进行重定向以具有前导 www,而 sub.another.com 已别名为 domain.com 以不具有前导 www。我找到了一个 solution,它有点管用。
我的前辈告诉我,仅插入符匹配(例如
RewriteRule ^
部分)在.htaccess中不起作用,显然只在虚拟主机中起作用。我知道它们之间存在一些细微差别,但我找不到任何来源(他也无法提供)说^
匹配在.htaccess中不起作用。
显然,正确的规则是
RewriteRule ^(.*) https://sub.another.com/$1 [R=301,L]
。谁能解释为什么匹配在 .htaccess 中不起作用?如果相信互联网,^
和^(.*)
应该匹配整行。后者明确指示匹配行首之后的任何内容,而前者匹配行本身的开头(因此也应匹配空字符串,请参阅this answer)。
我的前辈告诉我,仅插入符号匹配(例如
部分)在RewriteRule ^
中不起作用,显然只在虚拟主机中.htaccess
那是废话。
^
(正则表达式语法)只是断言字符串的开头。而已。因此,如果参数采用正则表达式(无论上下文如何),^
总是会“起作用”,具体取决于您要匹配的内容。 (我想知道你是不是真的指 URL 路径上的斜杠前缀?)
显然只在虚拟主机中
你可以说事实恰恰相反。
^$
将在 .htaccess
中匹配,但不会在虚拟主机上下文中匹配。 (这与 .htaccess
上下文中的根目录/主页匹配。)
这仅仅是由于在这些不同的contexts中匹配的内容。 (Apache 配置中有 4 个上下文:
.htaccess
、directory、virtualhost 和 server。)
在 virtualhost 上下文中,
RewriteRule
pattern 匹配完整的根相对 URL 路径,以斜杠开头。因此,您需要匹配 ^$
而不是 ^/$
(以匹配根目录)。
而在
.htaccess
(和 directory)上下文中,匹配的 URL 路径是相对于包含 .htaccess
文件的目录(目录前缀已被删除),因此 not 以一个斜线。
例如,给定网址
https://example.com/foo/bar/baz
...
在虚拟主机上下文中,
RewriteRule
pattern 匹配 URL 路径/foo/bar/baz
(以斜杠开头的完整 URL 路径。)
在根目录的
.htaccess
中,然后RewriteRule
pattern匹配foo/bar/baz
(无斜杠前缀)。但是如果 .htaccess
文件位于 /foo
子目录(不是根目录)中,那么匹配的 URL 路径是:仅bar/baz
(省略/foo
)。
显然,正确的规则是
。任何人都可以解释为什么比赛在RewriteRule ^(.*) https://sub.another.com/$1 [R=301,L]
中不起作用吗?.htaccess
这确实在
.htaccess
中工作。事实上,这只会在 .htaccess
中正常工作,因为如果您在 virtualhost 上下文中使用此规则,那么您将在重定向请求中的 URL 路径的开头以双斜杠结束。 (当然,其他规则可以影响此行为,.htaccess
文件的位置 - 如果在子目录中 - 也会改变此行为。)
如果相信互联网,
和^
应该匹配整行^(.*)
^
本身并不 match 任何东西,它只是断言字符串的开头,所以总是“成功”。而 ^(.*)
断言字符串的开头,然后匹配 URL 路径的其余部分并在反向引用中捕获它。事实上,^
中的 ^(.*)
前缀是完全可选的(匹配 URL 路径时),因为正则表达式是 greedy。 ^(.*)
和 (.*)
是“相同的”。
由于您在
substitution字符串中使用了
$1
反向引用,因此您需要实际捕获某些内容,因此您需要 (.*)
(因为 ^
不匹配/捕获任何内容,它只是一个 assertion)。但这都是一样的,无论您在哪里使用此指令:.htaccess
或 virtualhost.
在此特定规则中,您可以仅使用
^
并在 substitution字符串中使用
REQUEST_URI
服务器变量。例如:
RewriteRule ^ https://sub.another.com%{REQUEST_URI} [R=301,L]
请注意,
REQUEST_URI
变量包含整个 URL 路径,包括斜杠前缀,因此在 substitution 字符串中省略了斜杠。该规则可以说比使用反向引用(您上面的规则)“更好”,因为它适用于anywhere(任何目录),无论上下文如何,并且使用更有效的正则表达式。