我今天更新了 Apache(至 2.4.56-1),以前可以正常工作的大量 .htaccess 重写现在出现 AH10411 错误,与查询中的空格有关。我正在寻找“正确”的解决方案……
我今天更新了 Apache(至 2.4.56-1),以前可以正常工作的大量 .htaccess
重写现在都收到 AH10411 错误,与查询中的空格有关。我正在寻找“正确”的解决方案。
用户点击一个链接,如 <a href='FISH%20J12345.6-78919'>clickme</a>
你所见,链接 URL 中的空格已被编码为 %20
.
相关服务器目录中的文件包含并执行该相关指令 .htaccess
:
RewriteRule ^(FISH\s*J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1 [L,QSA]
(在上面,我检查的是空格,而不是 %20
,因为浏览器似乎在满足此规则之前将其转换为空格)。
在我更新 Apache 之前,这个功能一直有效;现在用户收到 403 错误,并且我的 Apache 错误日志报告:
AH10411:重写的查询字符串包含控制字符或空格
这似乎是一个新的错误,因为用谷歌搜索没有找到任何结果!
编辑我的页面(例如)将空格更改为下划线并正确处理它实际上不是一个选择,因为设计旨在支持用户能够使用他们关心的对象的名称直接输入 URL。到目前为止,我发现的唯一解决方法有点丑陋,即在正则表达式中分别捕获源名称的两个部分,因此:
RewriteRule ^(FISH)\s*(J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1+$2 [L,QSA]
^ ^ ^^^
(我 $1%20$2
最后尝试了一下,也出现了同样的错误。)
有没有更好的解决方案?例如,当我想要捕获 URL 中的空格并将其作为参数传递给底层页面时,我应该如何处理它?
(我最后尝试了 $1%20$2,但结果也很糟糕)。
这看起来像是一个错误。将 空格 为 %20
查询字符串中的形式应该是有效的。您也可以将 空格 为 +
查询字符串中的形式(如您的解决方法中所述)。
在您的原始规则中,Apache 在进行内部重写时应该将空格编码为 %20
(因为文字空格在 URL 中无效)。但是,Apache 似乎对编码空格犹豫不决(或者在重写中不自动编码 URL)?!
您可以尝试 B
在原始规则中使用标志。该 B
标志告知 mod_rewrite 在将其应用于 替换 字符串之前对反向引用进行 URL 编码。但是,这似乎取决于 Apache 对 +
查询字符串中的空格进行编码(而不是 %20
通常的做法)。当然,在早期版本的 Apache 中,这只会导致 Apache 将空格编码 为 ( %20
不要 +
),但是,自 2.4.26 版以来,Apache 引入了一个新标志 BNP
( backrefnoplus
),它明确告知 Apache not 使用 +
,因此您会认为默认情况下它会使用 +
。(不幸的是,我现在无法自己测试。)
例如:
RewriteRule ^(FISH\s*J[\d.]+-?\+?\d+)$ myPage.php?sourceName=$1 [B,QSA,L]
(小问题...在正则表达式字符类中使用时,不需要使用反斜杠转义文字点。我还将数字范围缩小为简写 \d
。)
另外: 最后一组数字(用子模式表示)前 -
可以同时有 +
和 -?\+?
吗?看起来应该是其中一个(或者什么都没有)?例如。 [-+]?
.
有没有更好的解决方案?例如,当我想要捕获 URL 中的空格并将其作为参数传递给底层页面时,我应该如何处理它?
并非如此(尽管您的解决方案并不完全正确 明确 见下文)。在您的特定示例中,它仅包含 空格 ,您不需要 执行任何操作,因为 mod_rewrite 应该自动对任何无效的 URL 进行 URL 编码。(有一个 - NE
- noescape
阻止 mod_rewrite 执行此操作 - 有时有必要防止已编码的字符被重复编码。)您始终可以 B
在这种形式的 URL 重写中使用该标志(如上所述)。 如果存在其他特殊字符,例如 需要 B
使用该 &
,否则这些字符不会被 URL 编码(实际上导致 URL 参数值被截断)。
RewriteRule ^(FISH)\s*(J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1+$2 [L,QSA]
请求中 有 0 个(即 \'none\')或更多 空格 空格 。这与您的原始指令不同,原始指令会保留原始请求中的空格(或缺少空格)。
初始请求中是否可以有 0 个或更多空格?
如果是,并且需要保留这些,那么重复此规则可能更容易,因为您需要尽可能多的“空格”。您可以实施搜索/替换,但这可能有点过头了。
(在上面我检查的是空格,而不是 %20,因为浏览器似乎在遵守此规则之前将其转换为空格)。
模式 RewriteRule
的 URL 路径 首先进行 URL 解码(% 解码),这就是为什么您需要匹配文字 空格 而不是 %20
。这与 \'浏览器\' 无关。URL 路径中的 空格 %20
在离开浏览器/用户代理的 HTTP 请求中一样,否则它就是无效的。
有一条评论(已 删除 ),其中用户还在 +
URL 路径中传递了(文字加号),似乎希望将其按原样传递给查询字符串(通过内部重写),然后将其视为编码空格 。 但是,使用 B
标志(如上所述)会导致文字 +
被 URL 编码为,从而 %2b
保留文字 +
- 这通常是正确的行为。但是,如果 +
应按原样复制,从而在生成的查询字符串中将其视为编码 空格 (而不是文字 +
),那么您可以限制标志将编码的非字母数字字符 B
(需要 Apache 2.4.26+)。即排除 +
.
例如,你可以将编码限制为 仅 空格 ?
。例如:
RewriteRule ^(.+)$ index.php?query=$1 "[B= ?,L]"
+
将不再在反向引用中编码,因此其在查询字符串中的特殊含义(作为编码 空格 )仍然适用。
注意:您不能只编码 空格 (因为空格不能用作 B
标志值参数中的最后一个字符),因此需要附加 ?
字符。因此,标志参数需要用双引号括起来,因为 空格 是参数分隔符。
参考: