^ 字符不工作 mod 在 htaccess 中重写

^ character not working on mod rewrite in htaccess

我在 .htaccess 文件中的重写规则遇到了这个非常烦人的问题。

上下文

所以我想要的是将这两种类型的 URL 重写到不同的目标:

URL 1 -- http://example.com/rem/call/answer/{Hex String}/{Hex String}/
URL 2 -- http://example.com/answer/{Hex String}/{Hex String}/

这是我的 .htaccess 文件的摘录:

RewriteEngine On
RewriteRule rem/call/answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET1
RewriteRule answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET2

问题

现在的问题是 URL 2 重写得很好(使用 规则 #2)并转到 TARGET 2,但是 URL 1 重写了两条规则,而不仅仅是 rule #1.

我尝试了几种解决方案,包括明显使用字符 ^ 作为 “字符串开头”。那时,我的重写规则是:

RewriteEngine On
RewriteRule rem/call/answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET1
RewriteRule ^answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET2

然而,另一个问题发生了。这次是 URL 1 重写得很好,只有 rule #1 并转到 TARGET 1。但是现在 URL 2 根本不再重写了。我猜这是因为第二个重写规则从不匹配任何 url 因此永远不会应用。

到目前为止我找到的唯一解决方案是删除 ^ 并在 规则 #1 末尾使用 [L] 标志,如下所示:

RewriteEngine On
RewriteRule rem/call/answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET1 [L]
RewriteRule answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET2

这样,它使用规则 #1,匹配,但永远不会达到规则 #2。两个 urls 都用这些规则正确重写了,但这不是一个好的解决方案,因为我可能不想在第一个之后停止 URL 1 的重写规则适用(如果我有第三条规则我也想应用它...)


我想问你的问题

既然我已经陈述了问题,我的问题是:

  1. [L] 标志是唯一的出路吗? (我非常怀疑,当然希望不会)
  2. ^ 会是一个候选解决方案吗? (我也这么认为)
  3. 如果是这样,如何让它工作以及为什么在我的情况下它根本不起作用?

我怀疑的是

我怀疑这与 URL 实际上是 http://example.com/answer/{Hex String}/{Hex String}/ 而不仅仅是 answer/{Hex String}/{Hex String}/ 这一事实有关,这意味着 answer/.. 不是确实在字符串的开头,因此用 ^ 作为前缀是行不通的。

但这又让我想到了另一个问题:

如何告诉 apache 去掉 scheme+domain 部分的 url(即 http://example.com/)并将规则与 url 的其余部分匹配(例如 answer/{Hex String}/{Hex String}/) ?


编辑

我还应该补充一点,我已经尝试过基本的 alice-bob 示例。我的根目录中有一个名为 bob.html 的文件,.htaccess 文件中有以下规则:

RewriteRule alice.html$ /bob.html

这很好用,并在查询 alice.html 时显示 bob.html 页面。但是,如果我将规则更改为:

RewriteRule ^alice.html$ /bob.html

然后我在查询 alice.html 页面时收到 404 错误...

至于@anubhava的评论,我完整的.htaccess文件组成如下:

RewriteEngine On

[A bunch of RewriteRule that have nothing to do with the topic at hand
(don't contain any "answer" string in them and all work perfectly)]

RewriteRule rem/call/answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET1 [L]
RewriteRule answer/([a-f0-9]+)/([a-f0-9]+)/?$ /TARGET2

ErrorDocument 404 /404.html
Header set Access-Control-Allow-Origin "*"
SetEnv file_uploads On

好的,感谢@anubhava 的评论,我通过将 .htaccess 文件向下移动一级到 www 目录轻松解决了这个问题。

我还是很好奇为什么这解决了我的问题,所以我继续研究apache的重写是如何工作的。我不确定我是否了解了所有细节,但这是我发现的。

位置位置位置

当然,文件的位置当然很重要,尤其是像.htaccess这样的配置文件。但它甚至超越了简单的文件路径,原因如下:

  1. 首先,您需要记住 .htaccess 文件会影响它所在的​​目录及其所有子目录。因此,将全局 .htaccess 文件放在您网站的根目录下似乎是合乎逻辑的,因为它会影响所有子目录(即整个网站)。

  2. 要记住的第二件事是 public_html 目录(在我的例子中称为 www,只是一个符号 link 到 public_html) 是您网站内容的根文件夹。您可能可以访问它的父目录,但是您放在 public_html 目录之外的任何内容本身都不是您网站内容的一部分,您放在那里的任何资源都不会成为您网站层次结构的一部分(即不可访问通过 http://example.com/path/to/resource).

  3. 正则表达式选项 ^ 匹配字符串的开头,这里在 URL 重写的上下文中,它是所考虑的 URL 的开头。这还不是全部,Apache 似乎会根据 .htaccess 文件的位置来解析匹配。这意味着 ^ 不仅引用您作为规则的一部分编写的字符串的开头,而且实际上引用它相对于充当 "local root directory" 的 .htaccess 文件的实际路径对于该特定 .htaccess 文件中的所有重写规则。


例子

假设您有一个子目录(例如 http://example.com/sub/directory/)并且其中有两个文件:

http://example.com/sub/directory/.htaccess
http://example.com/sub/directory/bob.html

在此 .htaccess 文件中,您有如下重写规则:

RewriteRule ^tom.html$ /sub/directory/bob.html

此规则不会匹配 http://example.com/tom.html,正如您预期的那样 ^ 会起作用,而是会匹配 http://example.com/sub/directory/tom.html,因为这是 .htaccess 文件所在的位置.


结论

一般来说,假设您有一个重写规则,例如:

RewriteRule ^PATH$ /TARGET_PATH

这意味着该规则不会将 URL 与 ^PATH$ 匹配,而是实际上将其与 ^[Location of the .htaccess file]/PATH$

匹配

换句话说,.htaccess 文件的位置充当其中所有重写规则的一种基础 URL(与 html 中的基础标记非常相似) .

这就是为什么我的 ^ 重写规则不起作用的原因,因为我的 .htaccess 文件位于 public_html 目录之上,并且该父目录充当基础目录URL 我的规则。因此,该规则永远不会匹配任何 URL,因为它将它与从未访问过的路径进行比较(因为在网站的内容根目录之上)。

我希望这足够清楚,以帮助可能遇到我遇到的相同问题的任何人。

干杯