RewriteRule ^ppd-brands/generic/gen_id/([^/]*)$ /ppd-brands/generic/?gen_id=$1 [L]
只是一个前兆...虽然您的旧“丑陋” URL 的形式是 /ppd-brands/generic/?gen_id=Mjky,但理想情况下,您应该 重写 到处理请求的实际文件,例如。 index.php,而不是允许 mod_dir 向目录索引发出额外的内部子请求 - 这是我假设在这里发生的事情。
例如:
RewriteRule ^ppd-brands/generic/gen_id/([^/]*)$ /ppd-brands/generic/index.php?gen_id=$1 [L]
现在,您的主要问题......从旧的“丑陋”网址外部重定向到新网址。在这种情况下,您需要小心重定向循环,因为如果我们只是重定向,那么上面的重写将在无限循环中再次重写它。由于这个原因,您不能使用 mod_alias Redirect (正如另一个答案所暗示的那样)。 (并且 mod_alias Redirect 也无法匹配查询字符串 - 另一个原因。)
旁白: 由于我们更改了上述重写以在重写的 URL 中包含 index.php,这似乎与旧的“丑陋” URL 不同,我们或许可以通过简单的重定向来摆脱困境如果您使用的是 Apache 2.4(但 Apache 2.2 会导致冲突,因为 mod_dir 会为 index.php 发出内部子请求之前我们可以使用 mod_rewrite 处理 URL)。
我们只需要重定向初始请求,而不是我们已经重写的请求。我们可以通过检查REDIRECT_STATUS 环境变量来做到这一点,该变量在初始请求中为empty,并在第一次成功重写后设置为“200”(如200 OK HTTP 状态)。 (另一种方法是检查 THE_REQUEST,而不是动态/可重写 URL 路径。)
例如,在您现有的重写之前尝试以下操作:
# Redirect "old" to "new"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^gen_id=([^/&]*)
RewriteRule ^(ppd-brands/generic)/(?:index\.php)?$ /$1/gen_id/%1 [QSD,R=302,L]
请注意,为了匹配查询字符串,我们需要一个条件(RewriteCond 指令)来检查QUERY_STRING 服务器变量。 RewriteRule pattern 匹配的 URL 路径明显排除了查询字符串。
请求 URL 中的 index.php 是可选的,因此它匹配 /ppd-brands/generic/?gen_id=Mjky 或 /ppd-brands/generic/index.php?gen_id=Mjky(如果那是实际 URL)。
$1 反向引用只是为了节省输入/重复。当指令匹配时,这将始终包含ppd-brands/generic。我们可以对“gen_id”做同样的事情,但这可能会使 susbstitution 字符串看起来有点太神秘了。
%1 反向引用(注意 % 前缀)是对上次匹配 CondPattern 中捕获组的反向引用(而不是 $1,它引用 RewriteRule 模式),即。 gen_id URL 参数的值。
QSD 标志 (Apache 2.4+) 从重定向的 URL 中去除查询字符串。否则 gen_id=XYZ 将被传递到目标 URL。如果您仍在使用 Apache 2.2,那么您需要将 ? 附加到 substitution 字符串的末尾(本质上是一个空查询字符串)。例如。 /$1/gen_id/%1?
“魔法”实际上是检查REDIRECT_STATUS env var 的第一个条件。如上所述,这确保了我们只处理初始请求而不是重写请求,从而避免了重定向循环。
请注意,这目前是 302(临时)重定向。只有在测试后才更改为 301(永久),这可以正常工作。 301 会被浏览器持久缓存,因此可能会给测试带来问题。
澄清一下……只有在您更改了应用程序中的所有 URL 后,才应该实施这样的重定向。这种重定向只是简单地重定向搜索引擎、反向链接以及应该手动输入 URL 的任何人(不太可能)。