如何使用mod_rewrite&编码特殊字符Apache的?

时间:2009-01-19 23:54:22

标签: apache mod-rewrite escaping

我想为我的标记系统提供漂亮的网址以及所有特殊字符:+&#%和{{1} }。有没有办法用mod_rewrite执行此操作而不必对链接进行双重编码?

我注意到delicious.com和stackoverflow似乎能够处理单个编码的特殊字符。什么是神奇的公式?

以下是我想要发生的事情的一个例子:

=

会触发以下RewriteRule:

http://www.foo.com/tag/c%2b%2b

,tag的值为“c ++”

apache / mod_rewrite的正常操作不能像这样工作,因为它似乎将加号转换为空格。如果我将加号重复编码为'%252B',那么我会得到所需的结果 - 但它会造成凌乱的URLS,对我来说似乎非常hacky。

5 个答案:

答案 0 :(得分:26)

  

apache / mod_rewrite的正常操作不会像这样工作,因为它似乎将加号转换为空格。

我认为这不是正在发生的事情。 Apache正在将%2Bs解码为路径部分中的+ s,因为+是那里的有效字符。它在让mod_rewrite查看请求之前执行此操作。

然后mod_rewrite将您的请求'/ tag / c ++'更改为'script.php?tag = c ++'。但是在application / x-www-form-encoded格式的查询字符串组件中,转义规则与路径部分中应用的规则略有不同。特别是,'+'是空格的简写(也可以编码为'%20',但这是我们现在永远无法改变的旧行为。)

因此PHP的表单读取代码接收'c ++'并将其作为C空间空间转储到_GET中。

看起来这就是使用重写标志'B'。请参阅http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteflags - 奇怪的是它使用了或多或少相同的示例!

RewriteRule ^tag/(.*)$ /script.php?tag=$1 [B]

答案 1 :(得分:5)

我不确定我理解你的问题,但Apache的NE指令的RewriteRule(noescape)标志可能对你有用。基本上,它会阻止mod_rewrite自动转义您提供的替换模式中的特殊字符。 Apache 2.2文档中给出的示例是

RewriteRule /foo/(.*) /bar/arg=P1\%3d$1 [R,NE]
例如,

会将/foo/zed转换为重定向到/bar/arg=P1%3dzed,这样脚本/bar就会看到一个名为arg的查询参数,其值为{ {1}},如果它查看P1=zed(好吧,那不是真正的查询参数,那么起诉我;-P)。

至少,我认为它是如何运作的。 。 。我自己从未使用过那个特定的旗帜。

答案 2 :(得分:1)

我终于在RewriteMap的帮助下工作了。

在httpd.conf文件中添加了转义映射 RewriteMap es int:escape

并在重写规则

中使用它
RewriteRule ([^?.]*) /abc?arg1=${es:$1}&country_sniff=true [L]

答案 3 :(得分:1)

潜在的问题是,您正在从具有一个编码的请求(具体地,加号是加号)转变为具有不同编码的请求(加号表示空格)。解决方案是绕过mod_rewrite所做的解码,并将您的路径直接从原始请求转换为查询字符串。

为了绕过重写规则的正常流程,我们将原始请求字符串直接加载到环境变量中,并修改环境变量而不是正常的重写路径。它已经被编码了,所以当我们将它移动到查询字符串时,我们通常不需要担心编码它。然而,我们所希望的是对加号进行百分比编码,以便将它们正确地作为加号而不是空格进行中继。

规则非常简单:

RewriteEngine On

RewriteRule ^script.php$ - [L]

# Move the path from the raw request into _rq
RewriteCond %{ENV:_rq} =""
RewriteCond %{THE_REQUEST} "^[^ ]+ (/path/[^/]+/[^? ]+)"
RewriteRule .* - [E=_rq:%1]

# encode the plus signs (%2B)  (Loop with [N])
RewriteCond %{ENV:_rq} "/path/([^/]+)/(.*)\+(.*)$"
RewriteRule .* - [E=_rq:/path/%1/%2\%2B%3,N]

# finally, move it from the path to the query string
# ([NE] says to not re-code it)
RewriteCond %{ENV:_rq} "/path/([^/]+)/(.*)$"
RewriteRule .* /path/script.php?%1=%2 [NE]

这个琐碎的script.php确认它有效:

<input readonly type="text" value="<?php echo $_GET['tag']; ?>" />

答案 4 :(得分:1)

我遇到了mod_rewrite的类似问题,并在网址中加了+号。场景如下:

我们有一个带+符号的网址需要重写,如http://deskdomain/2013/08/09/a+b+c.html

RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1

struts action urlRedirect获取url参数,进行一些更改并使用url进行其他重定向。但是在req.getParameter(“url”)中,+符号变为空,参数url内容为 http://deskdomain/2013/08/09/a b c.html,导致找不到重定向404。为了解决它(从先前的答案获得帮助)我们使用重写标志B(逃避反向引用)和NE(noescape)

RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1 [B,NE]

B,将转义+到%2B,NE将阻止mod_write转义%2B到%252B(双转义+符号),所以在req.getParameter("url")=http://deskdomain/2013/08/09/a+b+c.html

我认为原因是req.getParameter(“url”)会为我们做一个unescape,+符号可以unescape为空。 您可以尝试unescape%2B一次到+,然后unescape +再次清空。

"%2B" unescape-> "+" unescape-> " "