1

在查看了这个关于百分比编码的先前 SO 问题之后,我很好奇哪种编码样式是正确的 -关于百分比编码的维基百科文章暗示使用+而不是%20空格,同时仍然具有application/x-www-urlencoded内容类型。

这让我认为+vs.%20行为取决于 URL 的哪一部分被编码。路径段与查询字符串的首选区别是什么?本规范的详细信息和参考资料将不胜感激。


注意:我假设非字母数字字符将通过 UTF-8 编码,因为一个字符的每个八位字节都变成一个%XX字符串。如果我在这里错了,请纠正我(例如 latin-1 而不是 utf-8),但我对URL 不同部分的编码之间的差异更感兴趣。

4

1 回答 1

4

这让我认为+vs.%20行为取决于 URL 的哪一部分被编码。

它不仅取决于特定的 URL 组件,还取决于该组件填充数据的环境。

'+'用于编码空格字符的使用特定于application/x-www-form-urlencoded格式,适用于在 HTTP 请求中提交的 webform 数据。它不适用于 URL 本身。

application/x-www-form-urlencoded格式由 W3C 在 HTML 规范中正式定义。这是来自 HTML 4.01 的定义:

17.13.3节处理表单数据,第四步:提交编码后的表单数据集

本规范未指定可与表单一起使用的所有有效提交方法或内容类型。但是,HTML 4 用户代理在以下情况下必须支持已建立的约定:

如果方法是“get”并且动作是一个HTTP URI,用户代理接受动作的值,附加一个'?' 到它,然后附加表单数据集,使用“application/x-www-form-urlencoded”内容类型编码。用户代理然后遍历此 URI 的链接。在这种情况下,表单数据仅限于 ASCII 代码。

• 如果方法是“post”并且动作是HTTP URI,则用户代理使用动作属性的值和根据enctype 属性指定的内容类型创建的消息来执行HTTP“post”事务。

第 17.13.4 节 表单内容类型,application/x-www-form-urlencoded

这是默认的内容类型。使用此内容类型提交的表单必须编码如下:

1.控件名称和值被转义。空格字符被 '+' 替换,然后保留字符被转义,如 [RFC1738] 第 2.2 节所述:非字母数字字符替换为 '%HH'、一个百分号和两个十六进制数字,代表 ASCII 码特点。换行符表示为“CR LF”对(即,'%0D%0A')。

2.控件名称/值按照它们在文档中出现的顺序列出。名称与值之间用“=”分隔,名称/值对之间用“&”分隔。

相应的 HTML5 定义(第 4.10.22.3 节表单提交算法第 4.10.22.6 节 URL-encoded 表单数据)更加精细和详细,但出于讨论的目的,jist 大致相同。

因此,在通过 HTTPGET请求而不是请求提交 webform 数据的情况下,webform 数据使用 URL组件POST进行编码application/x-www-form-urlencoded并按原样放置。query

根据RFC 3986:统一资源标识符 (URI):通用语法

生成 URI 的应用程序应该对与保留集中的字符相对应的数据字节进行百分比编码,除非 URI 方案特别允许这些字符表示该组件中的数据

'+'是保留字符:

reserved    = gen-delims / sub-delims

gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"

sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
            / "*" / "+" / "," / ";" / "="

query组件明确允许未编码的'+'字符,因为它允许来自以下的字符sub-delims

unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"

pct-encoded = "%" HEXDIG HEXDIG

pchar       = unreserved / pct-encoded / sub-delims / ":" / "@"

query       = *( pchar / "/" / "?" )

因此,在 webform 提交的上下文中,空格'+'在按原样放入query组件之前使用编码。URL 语法允许这样做,因为 的编码形式与组件application/x-www-form-urlencoded的定义兼容query

因此,例如:http://server/script?field=hello+world

但是,在 webform 提交之外,将空格字符直接放入query组件需要使用pct-encoded,因为' '不包含在unreservedsub-delims中,并且定义也没有明确允许query

因此,例如:http://server/script?hello%20world

类似的规则也适用于path组件,因为它使用了pchar

  path          = path-abempty    ; begins with "/" or is empty
                / path-absolute   ; begins with "/" but not "//"
                / path-noscheme   ; begins with a non-colon segment
                / path-rootless   ; begins with a segment
                / path-empty      ; zero characters

  path-abempty  = *( "/" segment )
  path-absolute = "/" [ segment-nz *( "/" segment ) ]
  path-noscheme = segment-nz-nc *( "/" segment )
  path-rootless = segment-nz *( "/" segment )
  path-empty    = 0<pchar>
  segment       = *pchar
  segment-nz    = 1*pchar
  segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
                ; non-zero-length segment without any colon ":"

因此,尽管path确实允许未编码sub-delims的字符,但'+'字符被按原样处理,而不是编码空间。 application/x-www-form-urlencoded不与path组件一起使用,因此必须将空格字符编码为和%20的定义。pcharsegment-nz-nc

现在,关于用于编码字符的字符集 -

对于 webform 提交,该字符集由 webform 编码算法(在 HTML5 中比在 HTML4 中更是如此)中定义的规则规定,该算法用于在将 webform 数据插入 URL 之前准备 webform 数据。简而言之,HTML 可以直接在自身中指定accept-charset属性或隐藏字段,否则 charset 通常是父 HTML 使用的 charset。_charset_<form>

但是,除了 webform 提交之外,没有正式的标准来说明使用 charset 对 URL 组件中的非 ascii 字符进行编码(另一方面,IRI语法需要 UTF-8,尤其是在将 IRI 转换为 URI 时) /网址)。在 IRI 之外,由特定的 URI 方案决定它们的字符集(HTTP 方案没有),否则服务器决定它想要使用哪个字符集。现在大多数方案/服务器使用 UTF-8,但仍有一些服务器/方案使用其他字符集,通常基于服务器的区域设置(Latin1、Shift-JIS 等)。已经尝试直接在 URL 和/或 HTTP 中添加字符集报告(例如Deterministic URI Encoding ),但这些并不常用。

于 2015-11-14T04:53:57.683 回答