如何在 url 中重写 '%25'

如何在 url 中重写 '%25'

我的网站软件将 URL 中的空格字符替换为“+”字符,正确的链接应为“http://www.schirmacher.de/display/INFO/How+to+reattach+a+disk+to+XenServer' 例如。

有些网站链接到该文章,但不知何故,它们的嵌入式编辑器无法处理编码,所以我在 httpd 日志文件中看到的实际上是

GET /display/INFO/How%2525252bto%2525252breattach%2525252ba%2525252bdisk%2525252bto%2525252bXenServer

这当然会导致 404 错误。似乎 '+' 字符被编码为 '%2b',然后 '%' 字符被编码为 '%25' - 多次。

由于对不同网站的不同页面有许多这样的引用,因此我想重写 URL,以便访问者获得正确的页面。

这是我的尝试,但没有成功:

RewriteRule ^(.*)%25(.*)$ $1%$2 [R=301]

它应该做的是:获取 %25 字符串之前的所有内容以及其之后的所有内容,并用中间的“%”连接这些字符串,然后重定向。

使用示例输入 URL,规则应重写为

/display/INFO/How%25252bto%2525252breattach%2525252ba%2525252bdisk%2525252bto%2525252bXenServer

然后是重定向,然后它应该重写为

/display/INFO/How%252bto%2525252breattach%2525252ba%2525252bdisk%2525252bto%2525252bXenServer

并再次

/display/INFO/How%2bto%2525252breattach%2525252ba%2525252bdisk%2525252bto%2525252bXenServer

等等。最后,经过多次重定向后,我应该离开

/display/INFO/How%2bto%2breattach%2ba%2bdisk%2bto%2bXenServer

这是一个有效的 URL,相当于 /display/INFO/How+to+reattach+a+disk+to+XenServer。

我的问题是表达式根本不匹配,所以它甚至没有替换 %25 的一次出现。

我知道重定向的次数是有限制的,而且我确实应该使用 [N] 标志,但是我甚至没有正确完成第一步。


@Ben Lee:感谢您的详细回答。我已经花了几个小时解决这个问题。以下是我发现的情况:

  1. 在 mod_rewrite 看到 URL 中的任何 '%25' 字符串之前,都会转换为 '%'。因此 RewriteRule ^(.)%25(.)$ 与 url 中的 '%25' 不匹配,它实际上匹配 '%2525'。

  2. 反斜杠的存在没有区别。似乎 '%' 符号在我的例子中不被解释为反向引用,可能是因为之前没有 RewriteCond 语句。但为了确保万无一失,最好使用它。

  3. 包含 [L,R=301] 的行不正确。它会尝试针对每个 %2b 匹配项进行重定向,但允许的重定向次数是有限制的,如果次数超过此限制,则重定向会失败。

以下是我正在使用的 mod_rewrite 行:

RewriteRule ^(.*)\%25(.*\%25.*)$ $1%$2 [N]
RewriteRule ^(.*)\%25(.*)$ $1%$2 [R=301,L]

RewriteRule ^(.*)\%2b(.*\%2b.*)$ $1+$2 [N]
RewriteRule ^(.*)\%2b(.*)$ $1+$2 [R=301,L]

第三行将用“+”字符替换除一个 %2b 序列之外的所有序列。当只剩下一个 %2b 序列时,第四行将匹配,从而强制重定向。

第一行和第二行基本相同,但带有 %25 序列。有必要为每个可能的字符序列设置一个带有 [R] 标志的规则,因为我还使用了 mod_proxy / mod_jk,并且重定向将确保将生成的 URL 再次提供给每个模块。否则 httpd 将尝试从磁盘获取 URL,而这在我的例子中会失败。

答案1

这是您的原始规则,[L]添加了表示“最后”的内容:

RewriteRule ^(.*)%25(.*)$ $1%$2 [L,R=301]

之后这里有几个问题。首先,RewriteRule模式中的百分号具有特殊含义;它们表示对 的反向引用的开始RewriteCond。您可以通过转义它们(使用反斜杠)来解决这个问题:

RewriteRule ^(.*)\%25(.*)$ $1%$2 [L,R=301]

其次,当您将 a 插入%到替换中时,它不会继续将其视为 uri 编码部分的一部分。它会转换为文字百分号。在您收到的原始 URL 中,第一个%25"也会转换为文字百分号。因此,上述规则将导致URL 中的文字%25为 s 或 文字,而不是解析为或。因此您必须自己手动解析这些。%2b%+

RewriteRule ^(.*)\%25(.*)$ $1%$2
RewriteRule ^(.*)\%2b(.*)$ $1+$2 [L,R=301]

25最后,由于初始 后不只有一个%,而是可能有很多 ,因此使用[N]表示“下一个”。这基本上意味着“从头开始该过程,但使用我的新 url 作为输入”。因此这将处理25百分比后的任意数量的 :

RewriteRule ^(.*)\%25(.*)$ $1%$2 [N]
RewriteRule ^(.*)\%2b(.*)$ $1+$2 [L,R=301]

注意:如果您在常规 Apache 配置中设置规则,则此方法应该有效。如果您将其设置为,则.htaccess根据正则表达式检查的字符串中会省略前导斜杠,在这种情况下,您必须自行将其添加回去:

RewriteRule ^(.*)\%25(.*)$ /$1%$2 [N]
RewriteRule ^(.*)\%2b(.*)$ /$1+$2 [L,R=301]

更新:我现在没有能力进行测试,但查看文档时,我刚刚看到一个NE“无转义”选项,它使百分比在结果中充当常规编码标记。如果我理解正确的话,这意味着规则可以简化为:

RewriteRule ^(.*)\%25(.*)$ $1%$2 [NE,N,L,R=301]

但同样,这未经测试,我从未真正使用过该NE标志,所以我可能误解了它。如果您测试它并发现它有效,请告诉我,我将删除此更新并修复上述答案以包含这个更简单的版本。

相关内容