You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache .htaccess移除.php后缀:第二组规则无限循环原因解析

Hey there, let's dig into why your second rewrite rule is causing an infinite loop, and break down the mod_rewrite logic that's behind this behavior.

First: How mod_rewrite Actually Works Under the Hood

Before jumping into your rules, it's critical to understand the core flow of Apache's mod_rewrite:

  • When a request hits your server, mod_rewrite runs through your rules in order, first checking any RewriteCond conditions attached to a rule. If all conditions pass, it executes the RewriteRule.
  • The [L] flag (short for "Last") stops processing the rest of the rules in the current set, but here's the gotcha: Apache will re-run the entire rule set against the rewritten URL. This is how internal rewrites work, but it's also the main cause of infinite loops.
  • The [END] flag (available in Apache 2.4+) is different: it completely stops all rewrite processing, no more loops.
  • Some variables like THE_REQUEST are immutable—they hold the original HTTP request line (e.g., GET /test.php HTTP/1.1) and never change during rewrite processing. Variables like REQUEST_URI or REQUEST_FILENAME, though, are mutable: they update to match the rewritten URL each time.

Why Your Second Rule Causes an Infinite Loop

Let's assume your second rule set looks something like this (a common problematic setup for hiding .php extensions):

# Problematic redirect rule
RewriteCond %{REQUEST_URI} \.php$
RewriteRule ^(.*)\.php$ /$1 [R=301,L]

# Internal rewrite rule
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [L]

Here's the loop breakdown:

  1. A user visits https://test.com/test.php. REQUEST_URI is /test.php, so the redirect rule triggers, sending a 301 to https://test.com/test.
  2. The browser follows the redirect and requests https://test.com/test. The internal rewrite rule kicks in, rewriting the URL to /test.php so the server can load the actual PHP file.
  3. Now, REQUEST_URI is updated to /test.php—and mod_rewrite runs the entire rule set again. The redirect rule triggers once more, sending another 301 to /test.
  4. This cycle repeats forever because the rewritten URL keeps matching the redirect condition.

The root issue here is using a mutable variable (REQUEST_URI) to check for the .php suffix. After the internal rewrite, REQUEST_URI reverts to the .php version, so the redirect rule fires again.

Why Your First Rule Works

Your first rule set likely uses the immutable THE_REQUEST variable instead of REQUEST_URI for the redirect check, like this:

# Working redirect rule
RewriteCond %{THE_REQUEST} \s/+(.*?)\.php[\s?]
RewriteRule ^ /%1 [R=301,L]

# Internal rewrite rule
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [L]
  • When the user first visits /test.php, THE_REQUEST is GET /test.php HTTP/1.1, which matches the condition, so the redirect fires.
  • When the browser requests /test, THE_REQUEST is GET /test HTTP/1.1—no .php in sight, so the redirect rule doesn't trigger. Only the internal rewrite runs, and there's no loop because the mutable variables don't trigger the redirect again.

Alternatively, your first rule might use the [END] flag instead of [L] for the internal rewrite, which stops all further processing after the rewrite, preventing the rule set from re-running.

内容的提问来源于stack exchange,提问作者user4447799

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:27:44