为什么 .htaccess 中的重定向不起作用?

为什么 .htaccess 中的重定向不起作用?

我有一个 Wordpress 网站。我想将 .php 网址重定向到没有 .php 后缀的网址。.htaccess 如下:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On


RewriteRule ^(.*)\.php$ "$1" [R=301,L,NC]


RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

但当我访问https://www.example.com/somepage.php,页面无法显示,浏览器显示如下错误:

The page isn’t redirecting properly

    An error occurred during a connection to www.example.com.
    
        This problem can sometimes be caused by disabling or refusing to accept cookies.

地址栏中的 url 变为 https://www.example.com/index

如果我将重写规则更改为:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On


RewriteRule ^(.*)\.html$ "$1" [R=301,L,NC]


RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

并参观https://www.example.com/somepage.html,成功重定向至https://www.example.com/somepage网页可以正常显示,为什么?

答案1

因为,由于重定向是无条件的,你最终再次重定向URL 已被重写为index.php(WordPress 前端控制器)。

当您请求时/somepage.php

  1. 您被重定向到/somepage(根据第一条规则)。重定向响应被发送回客户端。
  2. 在第二次请求时,由最后一条规则/somepage内部重写为/index.php。然后重写引擎重新开始(在目录语境)...
  3. /index.php被重定向到/index(根据第一条规则)。重定向响应被发送回客户端。
  4. 第三次请求/index在内部被/index.php最后一次重写。然后重写引擎重新开始...
  5. 转到 3(陷入无限重定向循环)。

在一个目录上下文(如.htaccess)重写引擎不会简单地单次传递脚本。它会循环执行,直到 URL 未经更改地传递。(除非您END在 Apache 2.4 上使用该标志,或者发生外部 3xx 重定向。)

更改为删除.html可以正常工作,因为您正在重写为/index.php,它不以结尾.html,所以重定向指令(删除.html)不匹配。

要解决此问题,您需要避免重定向重写的请求。您可以通过以下任一方式执行此操作:

  • END在最后一次重写时使用标志(Apache 2.4+),而L不是阻止重写引擎的任何进一步循环。尽管您应该避免更改库存 WordPress 指令(见下文),但这可能不是首选选项。这在 Apache 2.2 上也不起作用。

  • 或者,检查服务器变量.php的扩展THE_REQUEST(该变量包含 HTTP 请求标头的初始行,并且在重写请求时不会更改)。例如:

    # Remove ".php" extension on "direct" (not rewritten) requests only
    RewriteCond %{THE_REQUEST} [A-Z]{3,7}\s/[^?]+\.php(?:\?|\s|$) [NC]
    RewriteRule (.+)\.php$ /$1 [R=301,L,NC]
    
  • 或者,检查REDIRECT_STATUS环境变量,该变量在初始请求时为空,在第一次成功重写时设置为 200(如 200 OK HTTP 状态)(这比上面更复杂的正则表达式更简单)。例如:

    # Remove ".php" extension on "direct" (not rewritten) requests only
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule (.+)\.php$ /$1 [R=301,L,NC]
    

但是,您不应该编辑该部分内的代码# BEGIN WordPress,因为 WordPress 本身会尝试维护这一点,并且可能会在以后覆盖此代码。这条规则需要取消注释标记# BEGIN WordPress。您不需要重复RewriteEngine On文件后面出现的指令(在 WordPress 部分)。

您需要在测试之前清除浏览器缓存,因为错误的(永久)重定向很可能已被浏览器缓存。请先使用 301(临时)重定向进行测试,以避免缓存问题。

但是,仅凭这一点还不能让您访问.php没有扩展名的文件.php。因为无扩展名的 URL 需要在内部重写回文件.php

相关内容