如何将.htaccess规则合并到Apache动态子域配置中?
解决Apache站点配置中合并.htaccess规则的递归错误问题
我明白你遇到的问题了——把.htaccess里的重写规则直接移到站点配置的<Directory>段后出现了递归循环,这是因为服务器配置层面的重写规则和.htaccess里的执行逻辑有细微差别,尤其是重写后的请求会再次触发规则导致循环。
问题根源
当你在.htaccess里使用RewriteRule .* index.php/$0 [L]时,Apache处理重写后的index.php/xxx请求时,会识别到index.php是真实存在的文件,因此不会再次触发重写规则。但在服务器配置的<Directory>段中,重写后的请求会被重新评估,而index.php/xxx本身并不是一个真实的文件/目录,导致规则反复触发,最终引发递归错误。
解决方案
我们可以通过两种方式解决这个问题,推荐使用第一种(因为你的Apache 2.4.18版本完全支持):
方案1:使用[END]标志终止重写(推荐)
Apache 2.4及以上版本提供了[END]标志,它会在重写完成后完全终止所有重写处理,避免后续的规则评估,从根本上防止递归。
修改后的完整站点配置如下:
<Directory "/var/www/vhosts/*"> AllowOverride None # 禁用.htaccess,提升性能并避免规则冲突 Options Indexes FollowSymLinks MultiViews Require all granted RewriteEngine On # 仅当请求不是真实文件/目录时才重写 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # 使用END标志终止重写,防止递归 RewriteRule ^(.*)$ index.php/$1 [END] </Directory> <VirtualHost *> ServerAlias *.example VirtualDocumentRoot /var/www/vhosts/%-2+ LogLevel rewrite:trace5 ErrorLog /tmp/errors.log Alias /404.php /var/www/404.php ErrorDocument 404 /404.php </VirtualHost>
方案2:添加条件排除已重写的请求
如果你需要兼容更早的Apache版本(虽然你的版本不需要),可以添加一个条件,跳过已经指向index.php的请求:
<Directory "/var/www/vhosts/*"> AllowOverride None Options Indexes FollowSymLinks MultiViews Require all granted RewriteEngine On # 跳过已经以/index.php/开头的请求,避免递归 RewriteCond %{REQUEST_URI} !^/index.php/ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 [L] </Directory>
验证路由
配置完成后,你的路由示例会正常工作:
my.domain.example→/var/www/vhosts/my.domain/index.phpmy.domain.example/hello→/var/www/vhosts/my.domain/index.php/hellotest.example→/var/www/vhosts/test/index.phptest.example/world→/var/www/vhosts/test/index.php/world
内容的提问来源于stack exchange,提问作者Jack Wilsdon
相关产品推荐
相关产品推荐

