首页 > 解决方案 > 有条件地包括 Apache 配置

问题描述

在多域设置中,我使用具有以下条件的巨大 .htaccess 文件来跳过大量重写规则,具体取决于所请求 URL 的 HTTP_HOST。

RewriteCond %{HTTP_HOST} !^www\.example\.com$
## skip next 1000 rules, if we`re not on the .com domain.
RewriteRule .? - [S=1000]
RewriteRule ^foo https://www.example.com/bar [R=301,L]
...
RewriteCond %{HTTP_HOST} !^www\.example\.co\.uk$
## skip next 500 rules, if we`re not on the .co.uk domain. 
RewriteRule .? - [S=500]
RewriteRule ^foo https://www.example.co.uk/bar [R=301,L]
...

由于我有几个域,总共有大约 4000 条重写规则,我宁愿将配置拆分为几个文件并根据当前的 HTTP_HOST 加载这些文件。

是否可以在表达式中使用 include 指令而不是

"RewriteRule .? - [S=500]"

?

可能是这样的:

<If "%{HTTP_HOST} =~ ^www\.example\.com$">
    Include conf/com.rewriterules.conf
</If>

还是有更好的方法来解决这个问题?

标签: apache.htaccess

解决方案


我们无法更改服务器设置,因此维护重写规则的唯一方法是 htaccess。

你不能这样做,.htaccess因为你不能在文件中使用Include指令。.htaccess没有其他方法可以包含配置文件。有条件地包含它的唯一方法是使用<If>块。

您可能会将所有指令都放在<If>块内,而不是使用[S=1000]标志。然而,这并非没有严重的警告。虽然<If>表达式被提前处理,但块的内容在请求中<If>被合并较晚(“最后一个”)。事实上,在请求已经映射到文件系统之后,它似乎很晚才被合并。这意味着RewriteRule指令匹配解析的文件系统路径,而不是请求的 URL 路径!因此,这需要在任何RewriteRule指令中考虑 - 或更改为使用 mod_aliasRedirectRedirectMatch用于您的外部重定向,它们始终对请求的 URL 起作用。

您可以服务器配置中执行此操作(在块Include内使用指令<If>)。但同样的警告适用于上面提到的 -<If>块合并很晚

但是请注意,您的语法并不完全正确。如果您希望匹配正则表达式,那么您在正则表达式周围缺少斜杠分隔符。它应该是:

<If "%{HTTP_HOST} =~ /^www\.example\.com$/">
    Include conf/com.rewriterules.conf
</If>

或者使用更简单的字符串/等式比较:

<If "%{HTTP_HOST} == 'www.example.com'">
:

但是,与其使用<If>块,不如为每个域单独设置一个块,<VirtualHost>并且在每个 vHost 中,您可以简单地Include使用必要的文件。没有警告。


顺便说一句,但是...如果您的所有“重写规则”都是外部重定向(如您的示例中所示),这些请求将导致 404(即它们不存在),那么您不应该这样做Apache 配置中的所有这些重定向都以(.htaccess或服务器配置)开头。

它们应该在您的应用程序逻辑中,并且仅在您的应用程序确定它会导致 404 时“延迟”处理。这会优先考虑正常的网站流量,而不是优先考虑重定向。使用 Apache 配置中的重定向,它们会在每个请求上进行处理——这通常是不必要的。


RewriteRule ^foo https://www.example.com/bar [R=301,L]
:
RewriteRule ^foo https://www.example.co.uk/bar [R=301,L]

也许只是您的示例代码,但您不需要在RewriteRule 替换外部重定向时指定绝对 URL。它可能是根相关的:/bar.


推荐阅读