多.htaccess配置下子目录www转非www重定向失效解决方案
Apache mod_rewrite 模块的默认处理逻辑是:子目录下存在独立.htaccess文件且开启RewriteEngine On时,父目录配置的重写规则默认不会自动继承,且子目录规则会优先参与匹配。你子目录的伪静态规则携带了[L]标记(last规则,匹配后终止当前目录下的重写流程),访问/latest/路径下的请求会被子目录的伪静态规则直接捕获处理,根目录配置的www到非www301跳转规则完全没有执行机会,因此子目录路径下跳转失效。
方案1:子目录开启父规则继承(改动量最小)
直接编辑/latest/.htaccess文件,在RewriteEngine on的下一行添加规则继承配置,注意必须指定InheritBefore参数保证父规则优先执行,修改后完整子目录配置如下:
RewriteEngine on # 优先继承父目录重写规则 RewriteOptions InheritBefore RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([^/\.]+)/?$ index.php?page=$1 [L]
不要用默认的Inherit参数:该参数会将父目录规则插入到子目录所有规则的末尾,依然会被子目录规则的[L]标记拦截,无法触发跳转。InheritBefore会把父目录规则放到子目录规则最前面优先匹配,www跳转规则命中后会直接返回301,不会走到后续伪静态逻辑。
方案2:将域名级跳转放到虚拟主机配置(性能最优)
如果你持有服务器Apache配置的修改权限,直接把根目录中www转非www的301规则从.htaccess迁移到对应站点的VirtualHost配置段中。该位置配置的规则是全局生效的,不会被子目录的.htaccess规则覆盖,同时省去了目录级规则扫描的开销,性能比.htaccess高很多。修改完成后重启Apache服务即可生效。
方案3:子目录重复配置跳转规则(兼容低版本Apache)
如果你的Apache版本低于2.4,不支持InheritBefore参数,可以直接在子目录.htaccess的最顶部(伪静态规则之前)重复写一遍www跳转规则,修改后完整配置如下:
RewriteEngine on # 优先执行www到非www跳转 RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC] RewriteRule ^(.*)$ https://%1/latest/$1 [R=301,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([^/\.]+)/?$ index.php?page=$1 [L]
- 修改配置后先清空浏览器缓存,301是永久重定向,浏览器会本地强缓存之前的错误响应,很容易导致验证结果不准
- 推荐用curl命令做无缓存测试,执行
curl -I https://www.example.com/latest/1,查看返回的Location响应头是否为https://example.com/latest/1、状态码是否为301 - 测试阶段建议先把301临时改成302,等所有路径跳转、伪静态访问都验证正常后再改回301,避免错误规则被浏览器长期缓存。
内容的提问来源于stack exchange,提问作者Priya Patel

