重写规则以防止apache在到达htaccess之前解码url?

重写规则以防止apache在到达htaccess之前解码url?,apache,.htaccess,mod-rewrite,Apache,.htaccess,Mod Rewrite,我们有这样一个htaccess规则: RewriteRule ^(.*)/(.*)/(.*) ../app$1/scripts/api/index.php?fn=$2&$3 [L] 但是,在大多数情况下,Apache会在url到达此规则之前对其进行解码,因此类似于beta/list/&cat=red%20%26%20blue的url,htaccess将其视为beta/list/&cat=red&blue,因此我们得到cat='red'和blue=null进入index.php而不是ca

我们有这样一个htaccess规则:

RewriteRule ^(.*)/(.*)/(.*) ../app$1/scripts/api/index.php?fn=$2&$3 [L]
但是,在大多数情况下,Apache会在url到达此规则之前对其进行解码,因此类似于
beta/list/&cat=red%20%26%20blue的url,htaccess将其视为
beta/list/&cat=red&blue
,因此我们得到
cat='red'
blue=null
进入
index.php
而不是
cat='red&blue'

我已经了解到,解决这个问题的方法是在htaccess规则中使用服务器变量,如
%{REQUEST\u URI}
%{the_REQUEST}
,因为这些变量在使用之前不会被解码,但很难实现。重写规则中的问号让一切都变得疯狂,我不知道如何逃避它

有没有专家能帮我修正下面的规则,让我的行为和上面的一样

RewriteCond %{REQUEST_URI} ^(.*)/(.*)/(.*)
RewriteRule . ../app%1/scripts/api/index.php?fn=%2&%3 [L]

实际上,解决方案是使用名为
的特殊服务器变量&u请求

发件人:

请求

浏览器发送到服务器的完整HTTP请求行(例如。, “GET/index.html HTTP/1.1”)。这不包括任何额外费用 浏览器发送的标题此值尚未取消替换 (已解码),与下面大多数其他变量不同

下面是您的规则应该是什么样子

# don't touch urls ending by index.php
RewriteRule index\.php$ - [L]

# user request matching /xxx/xxx/xxx (with optional query string)
RewriteCond %{THE_REQUEST} \s/([^/\?]+)/([^/\?]+)/([^\?]+)(?:\s|\?) [NC]
RewriteRule ^ ../app%1/scripts/api/index.php?fn=%2&%3 [L,QSA]
请注意,您不应该使用相对路径进行内部重写,这可能会导致混淆。相反,请定义一个
RewriteBase
,使用绝对路径或从域根开始使用
/

更新
由于可以在url中对前斜杠进行编码,因此需要将
allowencodedslass
设置为
NoDecode
(或
上的
,但这是不安全的)。还请注意,由于存在错误,您必须将此指令放在虚拟主机上下文中,即使服务器配置上下文被认为是正常的(否则,它将被忽略)。默认情况下,
allowencodedslass
设置为
Off
。因此,Apache自动处理编码的斜杠并拒绝它们,而不将请求传递给
mod_rewrite
。请参阅官方文档。

谢谢Justin。这看起来很有希望,但我得到了404。你能解释一下第一条重写规则的原因吗?regex周围的
\s
用于什么?这肯定会通过原始请求中的查询字符串吗?我只是在代码中添加了解释。由于第二条规则,第一条规则防止内部重写循环。第二条规则与您在问题中要求的url格式匹配。这不包括查询字符串(但如果您希望包含它,我可以修改)。另外,
\s
是空格。我已经调整了答案,将查询字符串包含在问题的示例中。我已把它标为公认的答案。谢谢你的帮助!问题是,简单地添加
QSA
标志并不能像预期的那样工作,因为条件不需要查询字符串。如果存在查询字符串,则条件将不匹配。所以你也需要适应这种情况。在我的回答中查看最新的代码OK谢谢Justin。我有点紧张改变我的整个生活领域的配置,但我会调查,看看它如何进行。干杯