Apache htaccess 多条规则的多个重写条件

Apache htaccess 多条规则的多个重写条件

我接手了一个网站,发现之前的开发人员有多条.htaccess重写规则,这是一个简短的例子:

RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^(.*)/landing/(.*)/(.*)$ landing.php?page=$1&id=$2&mid=$3
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^(.*)/landing/(.*)$ landing.php?page=$1&id=$2
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^(.*)/landing$ landing.php?page=$1

所有规则的重写条件始终相同,有没有办法组合重写规则,以便只需写入一次条件?

我研究过跳过标志,但它没有可能的反向引用。据我所知,在这些条件下我不需要反向引用,但是,跳过是最好的方法吗?或者有没有关于如何实现这一点的最佳实践?(有人建议我使用 QSA 标志,但是,经过研究,我认为这与我想要实现的目标没有任何关系。)

答案1

RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$

当cPanel 自动续订 SSL(Let's Encrypt?)安全证书时,它会在每个指令之前自动注入这组混乱的条件RewriteRule。这些条件确保验证文件(续订 SSL 证书所需)可访问。

不幸的是,我无法弄清楚 cPanel 为何要这样做 - 这可能是一场维护噩梦,而且我遇到过因这些条件而被破坏的指令(不可否认的是,这些指令从一开始就不够完美)。(我曾尝试在 cPanel 论坛上提问,但从未得到过好的答复。)

...有没有办法将重写规则结合起来,这样条件只需要写一次?

是的。您可以将这些条件移至文件开头的单独块中.htaccess,然后撤销RewriteRule它们的含义,因此,当请求与模式不匹配时,不仅仅触发该事件(使用否定正则表达式)。当请求与模式匹配时,您可以阻止进一步重写。例如:

# BEGIN cPanel SSL CERT RENEWAL
RewriteCond %{REQUEST_URI} ^/[0-9]+\..+\.cpaneldcv$ [OR]
RewriteCond %{REQUEST_URI} ^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$ [OR]
RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$ [OR]
RewriteCond %{REQUEST_URI} ^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^ - [L]
# END cPanel SSL CERT RENEWAL

请注意删除!条件模式OR以及前三个条件中的附加标志。RewriteRule如果请求匹配,则 then 会阻止进一步处理 mod_rewrite 指令。

(在 Apache 2.4.8+ 中,这些指令可以完全移至服务器配置。借助RewriteOptions InheritDownBefore。)

然后,接着执行RewriteRule你之前的指令(虽然我添加了标志L):

RewriteRule ^(.*)/landing/(.*)/(.*)$ landing.php?page=$1&id=$2&mid=$3 [L]
RewriteRule ^(.*)/landing/(.*)$ landing.php?page=$1&id=$2 [L]
RewriteRule ^(.*)/landing$ landing.php?page=$1 [L]

您可能应该L在那些剩余的重写中加入标志。

如果您愿意,您还可以将这 3 个重写组合成一个指令,但这取决于您的应用程序是否处理空 URL 参数。

(有人建议我使用 QSA 标志,但是,经过研究,我认为这与我想要完成的目标没有任何关系。)

是的,这实际上与这个特定问题没有任何关系。QSA(查询字符串附加)标志允许您将请求中存在的任何查询字符串与您在RewriteRule 代换

答案2

问题:

例如,您有这样的条件和规则:

RewriteCond %{REQUEST_URI} ^(...COND_1...)$
RewriteCond %{REQUEST_URI} ^(...COND_2...)$
RewriteRule ^(...RULE_1_FROM...)$ (...RULE_1_TO...)

RewriteCond %{REQUEST_URI} ^(...COND_1...)$
RewriteCond %{REQUEST_URI} ^(...COND_2...)$
RewriteRule ^(...RULE_2_FROM...)$ (...RULE_2_TO...)

RewriteRule ^(...RULE_3_FROM...)$ (...RULE_3_TO...)

条件 #1 和 #2 相同,您需要在这些条件下应用规则 #1 和 #2。规则 #3 不依赖于条件 #1 和 #2,必须与这些条件分开。

解决方案:

如果您不想每次对每个规则重复条件 #1 和条件 #2,您应该进行 2 处更改:

变更 1.创建与 #1 和 #2 相反的条件:

RewriteCond %{REQUEST_URI} !^(...COND_1...)$ [OR]
RewriteCond %{REQUEST_URI} !^(...COND_2...)$

(我在这里添加了!s 和[OR]s)。

变更 2。您有 2 条规则与这些条件相关,因此请在所有条件后添加此行:RewriteRule ^ - [S=2]。方括号中的数字是规则您需要在这些条件下应用这些规则。如果您有 3 行规则,则应这样写,RewriteRule ^ - [S=3]依此类推。

完整代码如下:

RewriteCond %{REQUEST_URI} !^(...COND_1...)$ [OR]
RewriteCond %{REQUEST_URI} !^(...COND_2...)$
RewriteRule ^ - [S=2]
RewriteRule ^(...RULE_1_FROM...)$ (...RULE_1_TO...)
RewriteRule ^(...RULE_2_FROM...)$ (...RULE_2_TO...)

RewriteRule ^(...RULE_3_FROM...)$ (...RULE_3_TO...)

相关内容