apache mod-rewrite 反向引用不匹配

apache mod-rewrite 反向引用不匹配

我正在尝试测试 HTTP_HOST 的值是否作为 URI 的一部分存在。首先,我使用以下命令将该值捕获到反向引用中:

RewriteCond "%{HTTP_HOST}" "(.+)"

然后我用以下方法测试它的存在:

RewriteCond "%{REQUEST_URI}" "/foo/%1/bar"

如果第二个 RewriteCond 成功,则删除重写中的值:

RewriteRule "^foo/(.+)/(.+)$" "foo/$2" [L]

但是,对于类似这样的 URI:

http://foo/localhost/bar

第二个 RewriteCond 从未匹配,并且跟踪显示:

applying pattern '^foo/(.+)/(.+)$' to uri 'foo/localhost/bar'

RewriteCond: input='localhost' pattern='(.+)' => matched

RewriteCond: input='/foo/localhost/bar' pattern='/foo/%1/bar' => not-matched

那么,为什么 %1 反向引用不匹配?并且 rewrite:trace4 是否应该在第二个 RewriteCond 中扩展 %1?

答案1

您不能在正则表达式本身中使用 Apache 反向引用(出于同样的原因,您不能%{VAR}直接在正则表达式中使用语法)。在正则表达式中,/foo/%1/bar字符%1是按字面意思匹配的。(如果 Apache 在应用正则表达式之前执行了某种变量扩展 - 但实际上并没有 - 那么它就不是严格意义上的 PCRE 正则表达式。)

(这就是为什么您没有%1在日志中看到扩展内容。无论日志级别如何。)

但是,您可以使用内部反向引用(正则表达式语法)将请求的主机名 ( HTTP_HOST) 与请求的 URL 路径中的第二个路径段进行匹配。例如:

RewriteCond %{HTTP_HOST}@$1 ^([^@]+)@\1$
RewriteRule ^foo/([^/]+)/(.+) foo/$2 [L]

请注意,我将第一个捕获组从 改为 ,.+因为[^/]+这仅用于匹配单个路径段。否则,如果您有 URL,/foo/localhost/bar/baz那么localhost/bar将被捕获(因为+贪婪的),这将无法匹配主机名(尽管也许应该匹配)。

(补充:除非包含空格,否则不需要将所有参数都括在 中。在我看来,"太多"可能会使阅读更加困难。而且我删除了$RewriteRule 图案

在里面测试字符串 %{HTTP_HOST}@$1(支持变量扩展的“普通”字符串):

  • %{HTTP_HOST}是请求的Host标头
  • @只是一个任意字符,预计不会出现在主机名或路径段中
  • $1是从中捕获的第一个反向引用(第二个路径段)的值RewriteRule 图案

测试字符串然后与正则表达式进行匹配^([^@]+)@\1$

  • ([^@]+)与服务器变量匹配(并捕获)HTTP_HOST
  • @匹配@测试字符串
  • \1([^@]+)是一个内部反向引用(在正则表达式本身中),它与正则表达式中的第一个捕获组匹配,即(上面)捕获的值。

因此,以下形式的请求http://localhost/foo/localhost/bar(我认为您在问题中指的是这个意思)将导致状况测试:

  • localhost@localhost针对正则表达式^([^@]+)@\1$- 成功

而请求该表格http://localhost/foo/something/bar将导致:

  • localhost@something=~ ^([^@]+)@\1$- 失败

在旁边:

但是,这里可能还有其他问题,具体取决于您在这里做什么(以及为什么这样做)。如果结果/foo/bar是“虚拟” URL 路径,那么您大概在文件中也有一个前端控制器模式.htaccess- 但这个重写的 URL 不太可能被前端控制器拾取 - 这取决于如何实现。

如果生成的 URL 路径旨在映射到物理文件(例如/foo/bar.html),那么“格式错误”的 URL 形式也会映射到同一资源(可能会产生重复内容问题)。可以通过使用标志(在 Apache 2.4+ 上)来防止进一步重写,或者在重写之前测试文件是否存在来/foo/localhost/localhost/bar.html解决此问题。END

相关内容