htaccess中mod rewrite的^字符无法工作

3

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

背景

我想要让这两种类型的URL重写到不同的目标:

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

This is an extract of my .htaccess file:

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 却同时被两个规则重写,而不仅仅是 规则 #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只使用规则 #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

这样,它使用第一条规则匹配,但从未到达第二条规则。这些规则都可以正确重写url,但这不是一个好的解决方案,因为我可能不想在应用第一条规则后停止重写URL 1(如果我还有第三条规则也要应用到它上面怎么办...)

我的问题

既然我已经阐明了问题,我在这里的问题是:

  1. [L]标记是唯一的选择吗?(我非常怀疑,当然希望不是)
  2. 是否应该使用^?(我认为是的)
  3. 如果是,如何使其工作,为什么在我的情况下根本没有起作用?

我怀疑的问题

我怀疑这与URL实际上是http://example.com/answer/{Hex String}/{Hex String}/而不仅仅是answer/{Hex String}/{Hex String}/有关,这意味着answer /..实际上不在字符串的开头,因此在前面加上^就无法起作用。

但是又引发了另一个问题:

如何告诉apache去除方案+域部分的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

1
出于好奇,TARGET 中是否有“答案”? - Jon Lin
嗯...你说的“答案”是什么意思? - Dolma
它是否包含字符串“answer”?例如:RewriteRule ^answer/(.*)$ /some/path/answer/foo.php?您的规则目标中是否出现字符串“answer”? - Jon Lin
@anubhava 我编辑了我的问题,添加了完整 .htaccess 文件的结构。 - Dolma
1
是的,RewriteRule ^alice.html$ /bob.html 应该可以工作。难道它不应该在 www 目录中吗? - anubhava
显示剩余4条评论
1个回答

2

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

我仍然很好奇为什么这能解决我的问题,所以我继续研究了Apache的重写工作原理。虽然我不确定是否理解得全面,但是以下是我发现的内容。

位置位置位置

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

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

  2. 第二件事是要记住public_html目录(在我的情况下称为www,只是指向public_html的符号链接)是您网站内容的根目录。您可能可以访问其父目录,但是您放在public_html目录之外的任何资源不是您网站内容的一部分,这些资源将不会成为您网站层次结构的一部分(即无法通过http://example.com/path/to/resource访问)。

  3. 正则选项^匹配字符串的开头,在URL重写的上下文中,它是所考虑URL的起始位置。而且,似乎Apache相对于.htaccess文件的位置解析匹配。这意味着^不仅引用您编写的规则作为字符串的开头,而实际上参考其相对于.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 $进行匹配,而是实际上将其与^[.htaccess文件的位置]/ PATH$进行匹配。换句话说,.htaccess文件的位置作为其中所有重写规则的基本URL(类似于html中的基本标签)。
这就是为什么我的带有^符号的重写规则无法正常工作,因为我的.htaccess文件位于public_html目录上方,并且该父目录充当规则的基本URL。因此,该规则永远不会与任何URL匹配,因为它将其与从未访问的路径进行比较(因为在网站内容根目录之上)。
希望这足以清晰地帮助遇到我遇到相同问题的人。
干杯

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接