解决方案

解决方案

我需要一些帮助来创建重定向,我试图将所有字符替换-+,但两者都是特殊字符,并且只想在 URL 包含时执行此操作?s=

这是一个例子

example.com/?s=i-need-to-rewrite-this-url
example.com/?s=i+need+to+rewrite+this+url

这是我所拥有的,我已经尝试使用()""但没有用

RewriteEngine on
RewriteRule ^?s=(.*)\-(.*)$ ?s=$1\+$2 [L,R=301]

我很感激任何帮助。谢谢。

答案1

我试图将所有替换-+,但两者都是特殊字符

这些字符没有什么特别的“特殊”之处。至少,在它们将要使用的上下文中没有。-(连字符)是范围说明符在正则表达式字符类中使用时,否则它只是一个连字符,并且可以安全地在 URL 的查询字符串部分使用未编码的字符(我们不需要在正则表达式字符类中使用它)。+(加号)是一个正则表达式量词,但我们不需要在正则表达式中使用它,只需要在替换字符串(该RewriteRule指令的第二个参数,不是正则表达式)。这+是一个编码的空间当在 URL 的查询字符串部分使用时 - 我想您已经知道这一点,这就是为什么需要重定向请求(尽管由于这是 URL 参数值的一部分,所以很好奇为什么无法在应用程序中解析它)。

但有一点需要注意,因为+URL 是经过编码的空间我们确实需要在指令上使用NE( noescape) 标志RewriteRule来防止 mod_rewrite 在重定向响应中将 URL 编码+%2B(文字+)。 (对于我们可能从中捕获的任何其他 % 编码字符也是如此QUERY_STRING- 此服务器变量未经过 % 解码。)

RewriteRule ^?s=(.*)\-(.*)$ ?s=$1\+$2 [L,R=301]

RewriteRule 图案(第一个参数) 仅匹配 URL 路径,而不匹配查询字符串。因此,RewriteRule单独的指令永远不会匹配查询字符串。顺便说一句,?是一个特殊的正则表达式字符(前一个标记的 0 或 1 量词)并且^(前一个标记)不可量化,所以我很惊讶这是否会编译(导致 500 内部服务器错误)。正则表达式中的文字?需要使用反斜杠转义。

如上所述,NE此处需要标志。并且+不需要在替换字符串,因为它在这里没有特殊含义(它不是正则表达式)。此外,由于相对替换字符串(即?s=$1\+$2),除非您已经定义,否则RewriteBase这会导致格式错误的重定向。

为了匹配查询字符串,你需要一个额外的状况RewriteCond指令)并与服务器变量进行匹配QUERY_STRING。因此,作为第一次尝试,您可以执行以下操作:

# First attempt (inefficient when multiple "-" are present)
RewriteCond %{QUERY_STRING} ^s=([^&]*)-([^&]*)
RewriteRule ^$ /?s=%1+%2 [NE,R=301,L]

请注意,%1%2反向引用(与 等相反$1)包含从前面捕获的值条件模式RewriteCond指令),而不是RewriteRule 图案(在这种情况下仅匹配空字符串)。

(注意:您应该始终先使用 302(临时)重定向进行测试,以避免潜在的缓存问题,并确保在测试之前清除所有中间缓存。)

我假设s仅有的URL 参数。根据上述规则,后面的任何其他 URL 参数都将被丢弃。

然而,上面的代码效率很低,因为它会为 的每个实例触发一次外部重定向-。因此,您的示例/?s=i-need-to-rewrite-this-url会触发 5 次重定向。

解决方案

与上述方法不同,您应该-在内部递归替换除一个之外的所有项,并且仅在替换完所有项后才触发外部重定向(并替换最后一个项--。为此,我们需要进行额外的重写以执行内部替换。例如:

# Internally replace all but the last "-" with "+" in the URL param
RewriteCond %{QUERY_STRING} ^s=([^&]*-[^&]*){2}
RewriteCond %{QUERY_STRING} ^s=([^&]*)-([^&]*)
RewriteRule ^$ ?s=%1+%2 [N=20]

# Replace the last "-" and redirect
RewriteCond %{QUERY_STRING} ^s=([^&-]*)-([^&-]*)
RewriteRule ^$ /?s=%1+%2 [NE,R=301,L]

首先状况检查正则表达式的规则^s=([^&]*-[^&]*){2}只是确定 URL 参数值中至少有 2 个连字符s。(否则将跳过该规则并直接转到第二条/重定向规则。)第二条状况然后 捕获 最后 查询 字符串 的 相关 部分-, 然后 在 接下来 中 使用 这些 部分RewriteRule.

N标志使重写引擎立即重新启动。20对迭代次数设置了限制(Apache 2.4+) - 所以我假设连字符不超过 20+1 个(最后一个连字符在第二个/重定向规则中被替换)。

因为我们知道在处理第二条规则时 URL 参数中最多只剩下 1 个连字符,所以我将连字符添加到正则表达式字符类中作为优化,以避免不必要的回溯。


未来

有一个replaceApache 表达式新增函数,顾名思义,它允许您搜索/替换字符串中的字符,但我认为这在最新的公共版本中尚未实现。但这可能会允许您在单个规则中执行类似以下操作:

RewriteCond %{QUERY_STRING} ^s=[^&]*-
RewriteCond expr "replace(%{QUERY_STRING},'-','+') =~ /^s=([^&]+)/"
RewriteRule ^$ /?s=%1 [NE,R=301,L]

相关内容