本地URL重写与.htaccess配置:ERR_TOO_MANY_REDIRECTS问题
解决URL重写导致的ERR_TOO_MANY_REDIRECTS循环问题
看起来你遇到的是典型的URL重写循环问题——Apache不断在旧URL和新URL之间互相跳转,超出了浏览器的重定向次数限制。别慌,这通常是因为重写规则逻辑有问题(比如方向搞反了,或者没加防循环的条件),跟php.ini关系不大,咱们一步步来排查解决:
先理清重写的逻辑方向
你要实现的是两种URL的转换:
- 外部重定向:当用户访问旧的
articles.php?billet=516[...]时,自动跳转到新的articles/[...]516(告诉浏览器和搜索引擎使用新URL) - 内部重写:当用户访问新的
articles/[...]516时,Apache偷偷把请求转发到articles.php?billet=...(用户看不到真实的PHP文件)
如果规则写反了,或者没加防循环的条件,就会导致Apache反复执行重写和重定向,形成死循环。
正确的.htaccess规则示例
把下面的代码放到你网站根目录的.htaccess文件里(如果没有就新建一个):
RewriteEngine On # 规则1:将旧的动态URL重定向到新的静态URL(外部跳转,告诉浏览器换URL) # 用%{THE_REQUEST}匹配原始请求,避免重写后的请求再次触发这条规则 RewriteCond %{THE_REQUEST} ^GET\ /articles\.php\?billet=(\d+)(.*) [NC] RewriteRule ^ /articles%2-%1? [R=301,L] # 规则2:将新的静态URL内部重写到实际的PHP文件(用户看不到跳转) # 先判断请求的不是真实存在的文件或目录,避免影响图片、CSS等静态资源 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^articles/(.*)-(\d+)$ /articles.php?billet=$2$1 [L]
规则细节解释:
%{THE_REQUEST}:这个变量存储的是用户发送的原始请求行(比如GET /articles.php?billet=516[...] HTTP/1.1),它不会被重写规则修改,用它匹配旧URL可以完美避免循环。R=301:表示永久重定向,适合SEO优化;如果你还在测试阶段,可以先用R=302临时重定向,避免浏览器缓存错误规则。L:表示这条规则匹配后就停止执行后续规则,防止规则冲突。!-f和!-d:确保当用户访问真实存在的文件或目录时,不会触发重写规则,比如你的网站有articles目录的话就不会被影响。
必要的排查步骤
- 确认mod_rewrite已启用:
打开httpd.conf,确保LoadModule rewrite_module modules/mod_rewrite.so这一行没有被注释掉(前面没有#)。同时,你的网站目录对应的<Directory>块里要设置AllowOverride All,这样.htaccess才能生效:<Directory "/path/to/your/site"> AllowOverride All # 其他配置... </Directory> - 清除浏览器缓存:
301重定向会被浏览器缓存,之前的错误规则可能还在生效。可以用浏览器的隐私模式测试,或者手动清除缓存。 - 调试重写规则:
本地环境可以开启重写日志,查看规则的执行过程:- 对于Apache 2.4及以上版本,在httpd.conf里添加:
LogLevel rewrite:trace3
- 对于Apache 2.4及以上版本,在httpd.conf里添加:
常见错误避坑
- 不要直接用
REQUEST_URI匹配旧URL,因为REQUEST_URI会被重写规则修改,很容易触发循环。 - 不要忘记加
!-f和!-d的条件,否则静态资源会被错误重写。 - 确保新URL的格式和规则里的正则匹配一致,比如你的新URL是
articles/[slug]-[id],正则里的(.*)-(\d+)就是匹配slug和id的顺序。
内容的提问来源于stack exchange,提问作者Charly Eveillard
相关产品推荐
相关产品推荐

