要将/pwreset.php 的直接请求从外部重定向到/reset-password,您可以在现有的内部重写之前执行以下操作:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^pwreset\.php$ /reset-password [R=301,L]
为了避免重定向循环,检查REDIRECT_STATUS env var 的条件是必要的,因为我们只想重定向用户发出的直接请求,而不是其他指令重写的请求。 REDIRECT_STATUS 在初始请求中为空,并在第一次成功重写后设置为“200”(如 200 OK)。
首先使用 302(临时)重定向进行测试以避免潜在的缓存问题。
UPDATE#1:有没有办法把它放在同一个规则中?因为页面很多,所以我实际上必须复制每一行。
不,如果您使用单个 .htaccess 文件并且您想通过 .htaccess 执行所有操作,那么您需要为每个外部重定向重复两个指令(RewriteCond 和 RewriteRule)。如果没有RewriteCond 指令(条件),重写的请求也会被重定向——创建一个无限循环。
但是,您可以在子目录中使用第二个.htaccess 文件来处理重定向。这将避免每个规则的附加条件。
例如,不是如上所述重定向pwreset.php。您可以在内部重写对.php 文件的所有请求(假设您没有直接访问任何 .php 文件)到包含另一个.htaccess 的子目录,其中包含必要的重定向。
-
将上面的重定向改成表单的重写:
# Rewrite all direct requests for `.php` files to a subdirectory
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+\.php)$ /redirect-handler/$1 [L]
其中/redirect-handler 是一个物理子目录。
-
使用必要的重定向创建/redirect-handler/.htaccess:
# Redirect direct requests for .php files to the canonical URL.
# If we are here then we know that the .php file has been called directly
# so do not need an additional condition before each rule.
RewriteEngine On
RewriteRule ^pwreset\.php$ /reset-password [R=301,L]
RewriteRule ^another\.php$ /canonical-url [R=301,L]
另一种选择是将请求重写为 PHP 脚本,而不是包含另一个 .htaccess 文件的子目录,而是在 PHP 中执行重定向。
例如,您最初的“重定向”变为:
# Rewrite all direct requests for `.php` files to PHP script
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !^/redirect-handler\.php$
RewriteRule (.+\.php)$ /redirect-handler.php?url=$1 [L]
然后,在/redirect-handler.php 中,您将检查$_GET['url'] var 以获取所请求的PHP 文件。 (或者只检查$_SERVER['REQUEST_URI'] 超全局。)查找所需的规范 URL,如果请求映射到有效 URL,则 301“重定向”或返回 404。
您可以更进一步,在 PHP 中管理所有内容 - 在单个脚本中。这有一个明显的优势,即您只有一个包含 PHP 文件/canonical-url 映射的列表(PHP assoc 数组或 DB 表)。除了.htaccess 中的初始重写之外,在添加/删除/更新 URL 时,您不需要更新 .htaccess。尽管您可能需要修改现有页面,具体取决于您包含文件等的方式(?)
UPDATE#2:使用单个 .htaccess 文件...如果您使用的是 Apache 2.4(而不是 2.2),那么您可以在内部重写时使用 END 标志(而不是 L 标志),这将避免在“重定向”上指定附加条件(RewriteCond 指令)。
例如:
RewriteEngine On
# Canonical redirects...
RewriteRule ^pwreset\.php$ /reset-password [R=301,L]
:
# Internal rewrites...
RewriteRule ^reset-password$ pwreset.php [END]
:
与L 标志不同,END 标志停止所有处理,从而防止重写引擎重新启动。
请注意,我对您最初的重写做了一些小改动...
- 删除了
NC 标志 - 你真的需要不区分大小写的匹配吗?否则,这可能会导致内容重复问题,但您应该始终链接到单个规范 URL。
- 删除了
RewriteRule 模式上的可选斜杠。 (原因同上。)
- 删除了
RewriteRule substitution 字符串上的斜杠前缀 - 它不是必需的并且简化了重写(它现在重写为文件系统路径 - 这就是它的本质 - 而不是 URL 路径)。
这比上面列出的方法要简单得多! (尽管这些方法仍然有其用途。)