将ReRriteRule重写为新URL并在内部重写为旧URL

时间:2013-02-12 21:50:46

标签: php apache .htaccess mod-rewrite url-rewriting

我的目标是从这些路径重定向用户:

/foo/index.php
/foo/

/index

/index加载/foo/index.php的原始内容。

这可能在.htaccess吗?

到目前为止,我已经尝试过:

RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]
RewriteRule ^index$ /foo/index.php [QSA,L]

但这会进入无限重定向循环。我认为为URI添加RewriteCond会有所帮助,但是来自docs

  

注意: RewriteRule模式匹配后正在处理条件。

显然RewriteCond在我的用例中没什么用处。

查看Rewrite Flags docsS标志似乎正是我正在寻找的内容:

  

如果当前规则匹配,则此标志强制重写引擎按顺序跳过下一个num规则。使用它来创建伪if-then-else结构:then子句的最后一条规则变为skip = N,其中N是else子句中的规则数。

所以我试过了:

RewriteRule ^index$ /foo/index.php [QSA,L,S=1]
RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]

虽然,因为我有L标志,S标志似乎有点多余。尽管如此,在我看来逻辑似乎是正确的,尽管这仍然是一个无限的重定向循环。

现在我正在使用PHP的解决方法。首先,Apache在内部将新URL重写为旧URL,然后在PHP中检查$_SERVER['REQUEST_URI']是否与脚本开头的新格式匹配,否则301重定向到新URL。

尽管如此,我想知道这是否仅仅与.htaccess有关?或者,如果有人能够解释我是如何/为什么通过上述重写规则获得无限循环,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

问题在于规则在.htaccess文件中,正如docs所说,此文件在每次重写循环后都会重新解析,因为它可能适用于.htaccess在另一个目录中。因此,你的L标志都是徒劳的。

我环顾四周,如果你真的无法将重写规则放在主apache配置中,我可以提供以下kludge:因为在重写运行之间没有更新Server-Variables THE_REQUEST,所以可以从那里结束“浏览器可见URL”并防止在那种情况下重写:

# external redirect to /index (unless browser already shows /index plus query params)
RewriteCond %{THE_REQUEST} !^\w+\ /index(\?.*)?\ HTTP/1..$
RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]

# internal redirect for /index
RewriteRule ^index$ /foo/index.php [QSA,L]

我认为还有另一个变量保持不变,但现在我找不到它。也许是其他人?