结合 1 个以上的 Apache 重写规则:虚拟主机域重定向和输入文件重定向

结合 1 个以上的 Apache 重写规则:虚拟主机域重定向和输入文件重定向

我在使用 Apache 的 RewriteCond 和 RewriteRule 条件时遇到了困难。我通常不经常使用它们,而且大多数文档都提供了足够的信息让我自己找到解决方案。但这次我遇到了如何组合多个重写情况的难题。

在 Apache 2.4.17 上,我有一个虚拟主机,其中多个 ServerAliases 都指向相同的 ServerName 和目录。每个配置的 ServerAlias 都应重定向到 ServerName 域。因此,当我访问 sub1.domain.com、sub2.domain.com 或 sub3.domain.com 时,它们都应通过 HTTP 301 重定向到 www.domain.com。

我还想将所有 URL 重定向到同一个 PHP 输入文件。例如:www.domain.com/news/1 应在内部重定向到虚拟主机的 documentroot 处的 index.php 文件,而无需更改用户 Web 浏览器中的 URL。

上述情况确实可以独立起作用,但是当我尝试在 .htaccess 文件中结合这些情况时,事情就出错了。

我的域名重定向示例:

AcceptPathInfo On
Options +MultiViews

Options +FollowSymLinks  
RewriteEngine On  

# Following solution inspired by https://makandracards.com/makandra/922-apache-redirect-all-requests-from-one-host-to-another
RewriteCond %{HTTP_HOST} !^www.domain.com$
RewriteRule ^(.*)$ "https://www.domain.com/$1" [NC,QSA,R=301]

效果很好。

这是我通常使用的代码,将所有 URL 内部重定向到 documentroot 处的 index.php,以便能够根据 URL 生成动态内容:

AcceptPathInfo On
Options +MultiViews

Options +FollowSymLinks  
RewriteEngine On  

RewriteCond %{SCRIPT_FILENAME} !-d  
RewriteCond %{SCRIPT_FILENAME} !-f  

RewriteRule ^.*$ ./index.php

这也很好用。请求不会在用户浏览器上转发到 index.php,而只会在内部转发。

当我尝试结合两个重定向时:

AcceptPathInfo On
Options +MultiViews

Options +FollowSymLinks  
RewriteEngine On  

# Following solution inspired by https://makandracards.com/makandra/922-apache-redirect-all-requests-from-one-host-to-another
RewriteCond %{HTTP_HOST} !^www.domain.com$
RewriteRule ^(.*)$ "https://www.domain.com/$1" [NC,QSA,R=301]

RewriteCond %{SCRIPT_FILENAME} !-d  
RewriteCond %{SCRIPT_FILENAME} !-f  

RewriteRule ^.*$ ./index.php

然后事情就出错了。对其他域(例如 sub1.domain.com、sub2.domain.com/test 等)的所有请求都会导致 Apache 错误:

永久移动

该文件已移至此处。

此外,尝试使用 ErrorDocument 处理请求时遇到 301 永久移动错误。

而 www.domain.com/test 正确地提供了文档根目录下 index.php 的内容。

当我尝试改变条件和规则的顺序时:

AcceptPathInfo On
Options +MultiViews

Options +FollowSymLinks  
RewriteEngine On  

RewriteCond %{SCRIPT_FILENAME} !-d  
RewriteCond %{SCRIPT_FILENAME} !-f  

RewriteRule ^.*$ ./index.php

# Following solution inspired by https://makandracards.com/makandra/922-apache-redirect-all-requests-from-one-host-to-another
RewriteCond %{HTTP_HOST} !^www.domain.com$
RewriteRule ^(.*)$ "https://www.domain.com/$1" [NC,QSA,R=301]

然后,sub1.domain.com 在用户浏览器中被正确重定向到 www.domain.com,但是当我向它附加一个 URI(如 sub1.domain.com/test)时,它会被重定向到 www.domain.com/index.php 而不是 www.domain.com/test,并且仅在文档根目录内部获取 index.php 的内容。

在这种情况下直接请求 www.domain.com/test 确实有效:显示文档根目录下的 index.php 内容,而不是将用户重定向到 index.php。

我相信这和一些标志有关,但不知道该如何应用它们。谁能告诉我要注意什么?

答案1

我认为我已经通过[L]在两RewriteRule行中添加标志来解决这个问题。

这是我现在的 htaccess 文件:

AcceptPathInfo On
Options +MultiViews

Options +FollowSymLinks  
RewriteEngine On 

# Following solution inspired by https://makandracards.com/makandra/922-apache-redirect-all-requests-from-one-host-to-another
RewriteCond %{HTTP_HOST} !^www.domain.com$
RewriteRule ^(.*)$ "https://www.domain.com/$1" [NC,QSA,R=301,L]

RewriteCond %{SCRIPT_FILENAME} !-d  
RewriteCond %{SCRIPT_FILENAME} !-f  

RewriteRule ^.*$ ./index.php [L]

据我了解,Apache 现在将首先考虑

RewriteCond %{HTTP_HOST} !^www.domain.com$

然后执行

RewriteRule ^(.*)$ "https://www.domain.com/$1" [NC,QSA,R=301,L]

由于RewriteRule已设置标志[L],Apache 将不会检查任何其他规则。

当完整的 URL 不符合要求时,第一个RewriteCondApache 将跳过该RewriteCond/RewriteRule组合并转到带有

RewriteCond %{SCRIPT_FILENAME} !-d  
RewriteCond %{SCRIPT_FILENAME} !-f  

RewriteRule ^.*$ ./index.php [L]

仅限内部重定向。现在它不会与第一个合并,RewriteRule因为RewriteRule它的[L]标志会被跳过。

我说得对吗?有人能确认或否认这个解释吗?或者可以澄清一下吗?

相关内容