我的虚拟主机中有以下用于 SSL 连接的内容(我的非 SSL 虚拟主机看起来相同,但没有设置用于重定向的第一个规则)。
DocumentRoot /var/www/example.com/public/
<Directory "/var/www/example.com/public/">
#only mod_rewrite configuration is shown here
RewriteEngine on
RewriteBase /
RewriteCond $1 !=signup
RewriteCond $1 !=login
RewriteCond $1 !=welcome
RewriteCond $1 !=thankyou
RewriteRule ^(.*)$ http://example.com/$1 [L,R,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.+)$ index.php?q=$1 [L,QSA]
</Directory>
我的目的是将任何不匹配(注册|登录|欢迎|谢谢)的页面请求重定向到非 SSL 虚拟主机而不进行进一步处理,否则不重定向,而是在 SSL 虚拟主机内处理请求。
第一个 RewriteRule 集负责重定向,而第二个 RewriteRule 集负责正常页面处理。
如果没有第一条规则集,所有请求都会在 SSL 虚拟主机下正确加载。
使用第一条规则集,重定向可以正常工作,但与列出的资源不匹配。例如,对
https://example.com/about
重定向至
http://example.com/about
但在请求注册、登录、欢迎和感谢页面时,问题就出现了。这些请求也会重定向到非 SSL 站点,但方式有问题。请求
https://example.com/signup
重定向至
http://example.com/index.php?q=signup
看起来第一个规则集不匹配(正如预期的那样),然后在处理第二个规则集之后,第一个规则集再次被应用(不是预期的)。
我无法将这种意外行为与任何记录的功能相匹配。
有任何想法吗?
编辑
我在文档中发现了一些模糊的引用,其中提到当“目录上下文”中发生规则匹配时,apache 会重新运行规则,但是,这些引用与 .htaccess 有关。我的重写发生在 <VirtualHost> 标签内的 <Directory> 标签内。我目前正在测试将重写移出 <Directory> 上下文 - 这肯定会改变行为,但我还没有让它按我需要的方式工作。
編輯2
这个问题肯定是由于当规则处理存在于目录上下文中时,apache 重新启动重写处理而引起的。我已将规则处理移出 <Directory> 标记。但是,现在 RewriteCond 行不起作用...例如。
RewriteCond %{REQUEST_FILENAME} -f
因为 apache 还没有使用 DocumentRoot 将请求的资源解析为文件映射。真是一团糟。
因此,我手动将我在 DocumentRoot 中指定的值添加到 RewriteCond 的前面。但是,这似乎是一个糟糕的黑客行为。例如。
RewriteCond /var/www/example.com/public%{REQUEST_FILENAME} -f
因此,现在我正在寻找一种方法来防止 apache 在目录上下文中重新启动重写过程,或者第二好的方法是,在 <VirtualHost> 级别指定必要的 RewriteConds。
答案1
我建议将以下内容添加到您的配置中,这将为您提供有关 mod_rewrite 正在做什么以及为什么这样做的详细日志。这可能有助于澄清您为什么会有这样的行为:
RewriteLog /tmp/rewrite.log RewriteLogLevel 9
一旦完成了分析,请务必删除这些行,因为它们会影响性能。
答案2
我决定采用以下解决方案,将重写放在任何 <Directory ...> 部分之外。这样我就可以将任何不应使用 SSL 的请求重定向到非 SSL 站点,同时允许通过 SSL 提供任何静态内容(图像、css、js 等)。
<VirtualHost ...>
...
RewriteEngine on
RewriteCond $1 !=signup
RewriteCond $1 !=login
RewriteCond $1 !=welcome
RewriteCond $1 !=thankyou
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/(.*)$ http://example.com/$1 [R=303,QSA,L]
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/(.+)$ /index.php?q=$1 [QSA,L]
...
</VirtualHost>