END标志在Apache 2.3.9+中彻底终止整个重写流程,防止重写后URI触发新一轮匹配;它不可用于.htaccess,不能与R、F、G、P、PT混用,且必须在主配置中使用。
在虚拟主机层级使用 mod_rewrite 时,[end] 标志位是防止规则被重复重写、避免循环的关键机制。它比 [l] 更彻底——不仅停止当前轮次的规则匹配,还终止整个重写引擎对当前请求的后续处理,防止因内部子请求或重定向引发的二次匹配。
为什么虚拟主机中容易出现规则循环
虚拟主机配置(<virtualhost></virtualhost>)中的 RewriteRule 默认作用于请求进入后的**初始处理阶段**。但若规则触发了内部重写(如重写到 PHP 脚本、或匹配了别名路径),Apache 可能会重新进入重写引擎(尤其在启用 FollowSymLinks 或配合 Alias 使用时),导致同一请求被反复匹配。常见诱因包括:
- 重写目标是同域下另一个 URL 路径(如
/article/123→/index.php?id=123),而/index.php又落在同一虚拟主机的 DocumentRoot 内; - 未显式终止,后续规则意外匹配重写后的新 URI;
- 与
RewriteCond中的%{REQUEST_URI}混用不当,条件判断基于原始 URI,但规则执行后 URI 已变,造成逻辑错位。
正确使用 [END] 替代 [L] 的典型场景
当你的重写目标是最终处理脚本(如前端控制器),且不希望 Apache 再次扫描该 URI 是否匹配其他规则时,必须用 [END]:
-
单页应用(SPA)HTML5 History 模式回退:
RewriteRule ^(.*)$ /index.html [END]—— 确保所有非静态资源请求都交由index.html处理,且不再被后续规则干扰; -
强制路由到入口脚本(如 Laravel、WordPress):
RewriteRule ^index\.php$ - [L]<br>RewriteCond %{REQUEST_FILENAME} !-f<br>RewriteCond %{REQUEST_FILENAME} !-d<br>RewriteRule ^(.*)$ /index.php?$1 [QSA,END]——[END]防止/index.php?...被再次捕获并陷入循环; -
安全路径拦截后静默终止:
RewriteRule ^\.git/ - [F,END]—— 返回 403 并彻底结束,避免某些模块(如 mod_negotiation)触发额外重写。
注意事项与常见陷阱
[END] 是 Apache 2.3.9+ 引入的标志,在旧版本中不可用(此时需降级用 [L] + 谨慎设计规则顺序,或升级 Apache)。另外需注意:
-
[END]不影响响应头或日志记录,只控制重写流程; - 它不能用于
.htaccess中的某些上下文(如部分共享主机禁用该标志),务必在虚拟主机配置中直接定义; - 若重写目标是外部 URL(含协议,如
http://),[END]无效,此时应使用[R=301,NE]显式跳转; - 调试时可启用
RewriteLog(Apache RewriteLogLevel 3 +RewriteLog(已弃用)或改用LogLevel alert rewrite:trace3(Apache 2.4+),观察是否仍有重复匹配行。
验证是否真正终止循环
最直接的方法是查看 Apache 错误日志(开启重写跟踪后):若某条规则命中后日志中不再出现后续 rewrite: 行,则说明 [END] 生效。也可构造测试请求,例如访问一个本应被重写的路径,用 curl -I 观察响应头中的 X-Redirect-By 或自定义头,并确认无 500 错误或超时——循环常表现为 Request exceeded the limit of 10 internal redirects 报错。

















