RewriteRule 附加不需要的字符串

RewriteRule appends unwanted string

我不想责怪 RewriteRule,但在我看来是这样。

最小的例子。在真正的代码中,第一个规则做了一些前置,所以它有一些意义,而不是这个。

RewriteRule ^(.*)$ 

RewriteCond %{REQUEST_URI} ^/pre
RewriteRule ^(.*)$ /post= [R=301,L]

当提交 URL 是 example.com/pre/sub 时,我得到 301 到 example.com/post=pre/sub/sub。我不知道第二个潜艇来自哪里。

我认为这应该有效的方式。第一条规则 </code> 是 <code>pre/sub,因此它将 pre/sub 重写为 pre/sub。 cond 检查 REQUEST_URI 是否以 /pre 开头并防止循环,最后一条规则匹配所有内容,因此 </code> 是 <code>pre/sub 并将其附加到创建 /post=pre/sub,然后它是重定向。但是浏览器得到 /post=/pre/sub/sub.

我做过的一些测试:

仅提交 example.com/pre 结果符合预期 /post=pre

当我修改示例为

RewriteRule ^(.*)$ --

RewriteCond %{REQUEST_URI} ^/pre
RewriteRule ^(.*)$ /post=&& [R=301,L]

结果重定向到 /post=&-pre/sub-/sub&,这意味着它附加 "after" 第一条规则,但 "before" 第二条。但是在哪里以及如何?

Pheeew...这让我有些头疼。经过一番挖掘后,我决定为 mod_rewrite 打开日志记录。 <my-docroot-path> 是我机器上文档根目录的绝对路径。

add path info postfix: <my-docroot-path>/pre -> <my-docroot-path>/pre/sub
strip per-dir prefix: <my-docroot-path>/pre/sub -> pre/sub
applying pattern '^(.*)$' to uri 'pre/sub'
rewrite 'pre/sub' -> 'pre/sub'
add per-dir prefix: pre/sub -> <my-docroot-path>/pre/sub
add path info postfix: <my-docroot-path>/pre/sub -> <my-docroot-path>/pre/sub/sub
strip per-dir prefix: <my-docroot-path>/pre/sub/sub -> pre/sub/sub
applying pattern '^(.*)$' to uri 'pre/sub/sub'

正如您在第 1 行和第 6 行中看到的,正在进行一些后缀处理。它显然将路径组件附加到当前处理的目录之上。当前处理的目录(.htaccess 的位置)是文档根目录 (/),所以它 "expects" 您处理当前目录级别的条目 (/pre)。完成处理后(使用 RewriteRule),它会将嵌套路径组件附加到该结果。

这就是为什么当您在同一目录级别处理请求时,不会产生任何问题,因为没有可附加的内容。

可以(并且官方建议这样做)通过向该 RewriteRule 指令添加 DPI 标志来修复。 DPI 表示 "Discard Path Info",它会丢弃嵌套的路径组件,这些组件将被添加到后缀中,因此不会附加任何内容。

或者...如果您不想更改嵌套路径,只需在替换字符串中包含当前级别 directory/file 名称即可。其余部分将后缀。这(至少对我而言)有点误导,因为该模式与整个路径匹配,但它希望您仅更改(包括在替换字符串中)当前级别 dir/filename。但这是有道理的...它为您提供了做出决定的上下文,并希望您仅更改 .htaccess 所属的目录级别的部分。

这是它的官方错误报告。
https://bz.apache.org/bugzilla/show_bug.cgi?id=38642

DPI 标志的文档
https://httpd.apache.org/docs/current/rewrite/flags.html#flag_dpi

还有一些其他有用的 SO 主题