我想为我的标记系统提供漂亮的网址以及所有特殊字符:+
,&
,#
,%
和{{1} }。有没有办法用mod_rewrite执行此操作而不必对链接进行双重编码?
我注意到delicious.com和stackoverflow似乎能够处理单个编码的特殊字符。什么是神奇的公式?
以下是我想要发生的事情的一个例子:
=
会触发以下RewriteRule:
http://www.foo.com/tag/c%2b%2b
,tag的值为“c ++”
apache / mod_rewrite的正常操作不能像这样工作,因为它似乎将加号转换为空格。如果我将加号重复编码为'%252B',那么我会得到所需的结果 - 但它会造成凌乱的URLS,对我来说似乎非常hacky。
答案 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-> " "