我接手了一个网站,发现之前的开发人员有多条.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...)