本文详解 `.htaccess` 中常见重写规则导致的 url 无限嵌套问题,通过修正 rewritecond 与 rewriterule 的逻辑顺序和匹配条件,实现安全、可靠的 php 文件无扩展名访问(如 `/page` → `/page.php`),同时阻止直接访问 `.php` 后缀并防止重定向循环。
在 Apache 环境中,许多开发者希望隐藏 PHP 文件扩展名以提升 URL 美观性与安全性(例如将 https://example.com/about.php 显示为 https://example.com/about)。但若 .htaccess 规则设计不当,极易引发无限重定向循环——正如问题中所示:浏览器地址栏持续拼接路径(/mv/project/mv/project/…),最终触发 500 错误或超时。
根本原因在于原始规则存在逻辑冲突与执行顺序缺陷:
- 第一组规则 RewriteRule ^(.*)$ $1.php 会将所有请求(包括已带 .php 的内部重写)无差别追加 .php;
- 而第二组规则 RewriteCond %{THE_REQUEST} … 本意是屏蔽直接访问 .php 的请求,但它在重写链中执行过晚,无法阻止第一组规则对已重写路径的二次处理;
- 更关键的是,^(.*)$ 是贪婪通配符,当 $1.php 对应的文件实际存在时,Apache 会再次匹配该规则(因为重写后的 URI 仍满足 ^(.*)$),从而形成死循环。
✅ 正确做法是:严格区分“内部重写”与“外部重定向”,并确保规则具备终止性与排他性。以下是经过生产环境验证的安全配置:
Options +FollowSymlinks
RewriteEngine On
# Step 1: 阻止用户直接访问 .php 文件(返回 404)
RewriteCond %{THE_REQUEST} \.php[\s?] [NC]
RewriteRule ^(.+)\.php$ - [R=404,L]
# Step 2: 将无后缀请求映射到对应 .php 文件(仅当文件真实存在时)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
? 关键说明: