什么情况下应该在HTTP URL中编码星号(*)?

36
根据RFC1738,星号(*)“可以在URL中未编码使用”:
因此,在URL中只能未编码使用字母数字、特殊字符"$-_.+!*'()"和用于其保留目的的保留字符。
但是,w3.org的命名和寻址材料指出,星号“保留用于在特定方案中具有特殊意义”,并暗示应对其进行编码。
另外,根据RFC3986,URL是URI的一种:
术语“统一资源定位符”(URL)指的是URI的子集,除了标识资源外,还提供了通过描述其主要访问机制(例如,其网络“位置”)来定位资源的手段。
它还指定星号是“子分隔符”,属于“保留集”中的一部分,并且:
URI生成应用程序应该对与保留集中的字符对应的数据八位组进行百分号编码,除非这些字符明确允许URI方案在该组件中表示数据。
它还明确指定更新了RFC1738
我理解为URL中需要对星号进行编码,除非它们用于URI方案定义的特殊目的。 RFC1738是否是HTTP URI方案的规范参考?它是否豁免星号编码,或者由于RFC3986而在这方面过时?

维基百科 表示:“当字符没有保留用途时,不需要进行百分比编码。”那么 RFC1738 是否取消了星号的保留用途?

各种资源和工具在这个问题上存在分歧。

PHP 的 urlencoderawurlencode-- 后者声称遵循 RFC3986 -- 对星号进行编码

然而,JavaScript 的 escapeencodeURIComponent 不对星号进行编码

Java 的 URLEncoder 不对星号进行编码

特殊字符 ".", "-", "*", 和 "_" 不改变。

常用的在线 工具(通过Google搜索“online url encoder”得到的前两个结果)也不对星号进行编码。URL 编码与解码工具 明确指出:“只有在特定情况下才需要对保留字符进行编码。”它接着列出了星号和和符号作为保留字符。它对符号进行了编码,但没有对星号进行编码。

在Stack Exchange社区中,其他类似的问题似乎有过时、不完整或不令人信服的答案:

考虑到这一切,HTTP URL中何时应编码星号?

13
你的问题涉及的研究比我希望回答所需的还要多。 - Edward Thomson
1个回答

20

##简短回答

当前URL语法的定义表明,在URL的路径、查询或片段组件中,您永远不需要对星号字符进行百分号编码。


HTTP 1.1

正如@Riley Major所指出的那样,HTTP 1.1引用的URL语法的RFC已经被RFC3986废弃,与最初引用的RFC相比,该RFC对星号的使用并不那么明确。

RFC2396(2005年1月之前的URL规范-原始答案)

在HTTP 1.1 URL中,星号*被列为“未保留字符”,因此永远不需要进行编码,这是RFC2396中定义URI语法所使用的。未保留字符允许在URL的路径组件中使用。

2.3. Unreserved Characters

Data characters that are allowed in a URI but do not have a reserved purpose are called unreserved. These include upper and lower case letters, decimal digits, and a limited set of punctuation marks and symbols.

   unreserved  = alphanum | mark

   mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"

Unreserved characters can be escaped without changing the semantics of the URI, but this should not be done unless the URI is being used in a context that does not allow the unescaped character to appear.

RFC3986(HTTP当前URL语法)

RFC3986修改了RFC2396,将星号作为保留字符,原因是“解码通常不安全”。 我对这个RFC的理解是未编码的星号字符允许在URL的路径、查询和片段组件中使用,因为这些组件没有指定星号作为分隔符(2.2. 保留字符):

这些字符被称为“保留字符”,因为它们可能(或可能不)被一般语法定义为分隔符......如果URI组件的数据与保留字符作为分隔符的目的相冲突,则必须在形成URI之前对冲突数据进行百分比编码。

此外,3.3 路径确认保留字符的一个子集(sub-delims)可以在路径段(由/分隔的路径组件的部分)中未编码地使用:

除了层次路径中的点段(“.”和“..”)外,通用语法认为路径段是不透明的。URI生成应用程序通常使用段中允许的保留字符。
例如,分号(“;”)和等于号(“=”)保留字符经常用于分隔适用于该段的参数和参数值。逗号(“,”)保留字符通常用于类似的目的。例如,一个URI生成器可能使用像“name;v=1.1”这样的段来表示对“name”的版本1.1的引用,而另一个可能使用像“name,1.1”这样的段来表示相同的内容。
HTTP 1.0参考RFC1738来定义URL语法,通过一系列更新和废止意味着它与HTTP 1.1使用相同的RFC进行URL语法。
就向后兼容性而言,RFC1738指定星号为保留字符,但由于HTTP 1.0在URL路径组件中未定义未编码的星号的任何特殊含义,因此如果您使用星号,则不应该破坏任何内容。这意味着您仍然可以安全地将星号放入指向最古老系统的URL中。
作为一个侧面说明,在HTTP规范中,星号字符在请求URI中确实有特殊含义,但是无法使用HTTP URL表示它。

The asterisk "*" means that the request does not apply to a particular resource, but to the server itself, and is only allowed when the method used does not necessarily apply to a resource. One example would be

   OPTIONS * HTTP/1.1
免责声明:我只是在阅读和解释这些RFC文件,所以可能会有错误。

感谢提供的信息。所以,即使RFC3986明确废弃了RFC2396,因为HTTP 1.1更早并引用了RFC2396,那么RFC2396仍然适用吗?只是想确认一下我的理解是否正确。这是否意味着PHP遵循RFC3986是“错误”的,还是他们只是试图覆盖更多不仅仅是HTTP URL的URL,冒着对HTTP URL进行过度编码的风险? - Riley Major
@RileyMajor - 嗯,我没有看到 RFC3986。看起来在 URL 的路径组件中仍然允许使用未编码的星号,尽管情况不是很明确:星号已被移到 sub-delims(2.2),并且在路径(3.3)下,sub-delims 是允许的字符类型之一。我会更新我的回答,并加入这个信息。 - Stecman
那么我的理解是正确的,星号在路径部分中被允许未编码,当它被用于其特殊含义时,但在查询部分中应该被编码吗? - Riley Major
@RileyMajor - 正如我在答案中所说的,根据RFC3986,未编码的星号允许出现在URL的路径、查询和片段标识符组件中。附录B中的正则表达式也证明了这一点。星号的特殊含义在HTTP URL中无法表示,因此它是不相关的(这只是一个额外的小提示-如果有些困惑,很抱歉)。 - Stecman

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