这让我认为+
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
,因为' '
不包含在unreserved
或sub-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
的定义。pchar
segment-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
),但这些并不常用。