为什么 Firefox 使用 apache mod-rewrite B 标志以不同的方式处理 urlencode?

为什么 Firefox 使用 apache mod-rewrite B 标志以不同的方式处理 urlencode?

最近我遇到了一个关于 urlencode 的奇怪问题,我的 url 的 pathinfo 和 querystring 部分恰好都有一个“+”。

例如:

http://example.com/A + B?s=C + D

我在 Firefox 中使用 tamperdata,并能确保 Firefox 已将 URL 编码为以下内容:

http://example.com/A%20+%20B?s=C%20+%20D

在服务器端,我使用以下指令启用了 apache url rewrite:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

然后,在 php 中,我得到以下内容:

$_REQUEST['q'] = 'A   B';
$_REQUEST['s'] = 'C   D';
$_SERVER['QUERY_STRING'] = 'q=A + B&s=C%20+%20D';

我们知道,php 会自动使用 urldecode 将查询字符串解析为 $_REQUEST 超级变量,这就解释了为什么 'A + B' 变成 'A B' 而 'C + D' 变成 'C D'。然后,我意识到 apache url rewrite 必须解码所有字符才能进行重写映射。旗B将有助于在映射之后重新编码它们。因此重写规则如下并应用了 B FLAG。

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [B,L,QSA]

那么结果就变成了:

$_REQUEST['q'] = 'A + B';
$_REQUEST['s'] = 'C   D';
$_SERVER['QUERY_STRING'] = 'q=A+%2B+B&s=C%20+%20D';

我预期的是以下情况:

$_SERVER['QUERY_STRING'] = 'q=A%20+%20B&s=C%20+%20D';

然后,我可以使用 rawurldecode 手动解析查询字符串如下,这也是 Firefox 最初的做法

$_REQUEST['q'] = 'A + B';
$_REQUEST['s'] = 'C + D';

但是 apache mod-rewrite B glag make q 却变成了 'A+%2B+B',这与原来 Firefox 的编码 'A%20+%20B' 不一样。当然,apache 的编码与 php urlencode 函数兼容。

那么问题是为什么 Firefox 和 Apache 的行为如此不同?为什么 Firefox 不将 'A + B' 编码为通常使用的 'A+%2B+B' 而是 'A%20+%20',这会导致与 PHP 和服务器端存在如此多的不兼容?

相关内容