为什么URL的编码和查询字符串部分的编码不同?

25

我正在研究为什么我的查询参数中有加号+而不是%20,以及为什么它们具有诸如%C3%BC的字符串,而不是像编码URL一样有一个ü(UTF-8)。

经过2小时的思考,我发现我的Web应用程序与URL编码标准不兼容,然后找到了一个结论:查询字符串的编码方案与URL(指没有查询字符串的部分)的编码方案不同。

举个例子:

  • URL:
    • 空格被编码为%20
    • UTF-8字符保持不变
  • 查询参数:
    • 空格被编码为+
    • UTF-8字符被编码为十六进制表示

那么,有人能告诉我为什么编码方案不同吗?毕竟查询参数也是URL的一部分啊。

参见:

3个回答

29
URIs最初起源于RFC 1630,使用百分号编码作为一种允许表示“不安全”字符的方法。这个最初版本实际上提到了ISO Latin 1字符集作为非ASCII字符的编码。那一年稍后,RFC 1738在定义URL时删除了对Latin-1的引用。
查询字符串格式实际上是一个不同的但相关的编码,application/x-www-form-urlencoded,在RFC 1866中与HTML 2.0一起定义。它基于RFC 1738,但指定空格(不是所有空格,只是ASCII代码为0x20的字符)被替换为“+”,并且行结束符被编码为CRLF(即%0D%0A)。前者可能是因为这样可以节省表单提交中非常常见的2个字节的字符,而以更少见的字符为代价使用额外的2个字节,后者是为了避免在使用不同的行结束符编码系统之间传输时出现问题。非ASCII字符未予考虑。

UTF-8编码在URI中出现的时间比较晚,是在RFC 3986中提出的,尽管早期的一些协议可能已经指定了这种或其他非ASCII字符的编码方式。为了保持向后兼容性,所有UTF-8八位字节必须进行百分号编码。伴随着RFC 3987的“国际化资源标识符”(IRI)定义了基本上是“允许大多数代码点160及以上未经编码”的“URI”,但仍然有许多协议需要URI。请注意,您上面的说法是不正确的,因为URL不能包含未编码的ü或任何其他非ASCII字符。

application/x-www-form-urlencoded以不同的方式进行了国际化。HTML5规范的application/x-www-form-urlencoded明确允许在查询字符串中使用任何ASCII兼容字符集,并且实际上不同的字段可以使用不同的字符集,但所有非ASCII八位字节仍必须进行百分号编码。当在IRI的查询部分中使用时,如果使用适当规范化的UTF-8作为字符集,则这些字符可能可以表示为未编码的形式,因为转换回URI将导致正确的application/x-www-form-urlencoded数据。


1

它们不一定需要不同,+是有效的路径字符,而ü是有效的搜索字符(根据RFC 3987)。您可能会看到浏览器或其他预设编码方案做出过时或过于谨慎的假设。


谢谢指引我查阅RFC 3987,但我想等待看是否有人能告诉我最初为什么要进行这种区分。此外,现在还出现了一个问题,即为什么所有主要的Java查询参数编码器都没有国际化,但这是另一个问题 :)。 - moritz

-1

在查询字符串参数方面,+%20之间没有区别:

空格被编码为“+”或“%20”

引用参考


1
这仅适用于查询字符串中的表单参数。 - Julian Reschke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接