【问题标题】:RewriteRule Last [L] flag not working?RewriteRule Last [L] 标志不起作用?
【发布时间】:2011-10-11 11:56:38
【问题描述】:
php_flag display_errors 1
php_value auto_prepend_file init.php
RewriteEngine on 
RewriteRule ^$  /id/authenticate [R]
RewriteRule ^login_openid$  /id/login_openid.php [QSA,L]
RewriteRule ^authenticate$  /id/authenticate.php [QSA,L]
RewriteRule ^facebook$  /id/facebook.php [QSA,L]
RewriteRule ^createfromopenid$  /id/createfromopenid.php [QSA,L]

RewriteRule .* - [L,R=403]

这是我的 .htaccess 文件。在 serverconfig 我只有AllowOVerride all

如果我请求 URL http://mydomain.com/id/authenticate,我会收到 403 错误。如果我删除最后一条规则,它会起作用。 [L] 单位不应该阻止任何进一步的规则发生吗?

编辑:

我的 htaccess 文件位于子文件夹“id”中,因此规则有效。

【问题讨论】:

  • 您声明除了最后一个匹配之外没有任何规则是一个有效的想法,但If I remove the last rule, it works. 暗示它们确实有效。此外,您确实假设我的 htaccess 文件位于 Web 根文件夹而不是子文件夹中,事实并非如此,也不是问题的上下文。但是我不需要你的帮助,因为你又错了。我刚刚在 serverfault 上找到了问题的正确答案:serverfault.com/questions/241907/… 原来 L 规则在重写规则匹配时不起作用。

标签: apache http mod-rewrite url-rewriting


【解决方案1】:

[L] 规则可以正常工作——您只是不知道它实际上是如何工作的。

当 Apache 看到 [L] 标志和规则匹配(发生重写)时,Apache 将进入 下一次迭代,并从顶部重新开始匹配 所有 规则。 [L] 标志的意思是“不处理任何低于在本次迭代中的规则”。

是的,Apache documentation 并不是 100% 清楚这一点(这意味着它可以改进),但提供了足够的信息来最终弄清楚。


Apache 在少数情况下会停止重写周期:

  1. 根本没有匹配的规则(没有发生重写);

  2. “立即退出”规则匹配(例如RewriteRule .* - [L]);

  3. 发生重写,但输入 URL 和最终 URL 相同(发生在第 2-3 次迭代时,“糟糕”的书面规则将相同的 URL 重写为相同的 URL。

    例如RewriteRule (.*) /index.php?page=$1 [L]:

    • /hello => /index.php?page=hello
    • 在下一次迭代中它将重写/index.php => /index.php?page=index.php
    • 在第 3 次迭代中,它将是 /index.php => /index.php?page=index.php .. 现在没有意义了);
  4. 已达到重写迭代限制(默认 = 10)——如果您进入了无限重写周期(该值由 LimitInternalRecursion Directive 控制)。


根据上述所有信息,我可以说您当前的规则确实按预期工作。这意味着您必须更改逻辑并摆脱最后一条规则(也许在父级 .htaccess 中处理这一时刻 .. 或以不同方式处理它——这一切都取决于您的应用程序是如何构建的,我不想做出疯狂的猜测)。

【讨论】:

  • @Joe - 作为目标 URL 意味着没有重写,这与 #3 几乎相同(迭代开始时的 URL = 迭代结束时的 URL)。由于 URL 根本没有改变,Apache 将退出循环。
  • 根据您的应用程序/重写逻辑,您可以使用以下规则:# do not do anything for already existing filesRewriteCond %{REQUEST_FILENAME} -f [OR]RewriteCond %{REQUEST_FILENAME} -dRewriteRule .+ - [L]——它工作正常。
  • @Joe 让我们根据您的规则举一个例子:请求 URL 是 /id/login_openid初始迭代: URL 被剥离到目录级别和 = login_openid。这将匹配规则 #2(第 5 行)。发生重写,新 URL 为 /id/login_openid.php,重写进入下一次迭代。 第 2 次迭代:URL 被剥离并 = login_openid.php。除了最后一条,它几乎没有规则,它告诉 Apache 中止请求(发送 403 响应)——这就是您当前规则的工作方式。
  • @LazyOne,嗯,上面提到的 hakre END 标志怎么样?
  • @Pacerier 是的,它应该可以完成这项工作(根据描述,它正是需要的),但它仅在 2.3.x 版本中可用——我个人还没有处理过它(所有服务器仍然是 v2.2 甚至更低版本)并且不知道它的普及程度。如果您控制整个服务器(可以安装该版本.. 或者已经安装),那么您绝对应该尝试一下。
【解决方案2】:

把它放在你的 cath all 规则前面。

RewriteCond %{ENV:REDIRECT_STATUS} !=200

问题是一旦处理了 [L] 标志,所有下一个 RewriteRules 确实被忽略了,但是,文件从头开始再次处理,现在使用新的 url。

如果文件已经被重定向,这个魔法条件将不会处理catch all

PS: 如果它不起作用,您可能需要稍微调整条件:200!=200^.^$
显然,该变量被设置为200 以进行重定向,但其他页面(错误和其他内容)也将其设置为某个值。现在这意味着您可以根据需要检查它是 is emptyis not emptyis 200 还是 is not 200

【讨论】:

  • 我遇到了一个非常相似的问题,这为我解决了这个问题,在我的 .htaccess RewriteCond %{ENV:REDIRECT_STATUS} !=200 RewriteRule .* /index.php [L]987654333@
猜你喜欢
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多