URL

现行标准 — 最后更新

参与:
GitHub whatwg/url (新问题, 打开的问题)
在Matrix上聊天
提交:
GitHub whatwg/url/commits
此提交的快照
测试:
web-platform-tests url/ (正在进行的工作)
翻译 (非规范性):
日本語
简体中文
한국어

摘要

URL标准定义了URL、域名、IP地址、application/x-www-form-urlencoded格式及其API。

目标

URL标准通过以下方法使URL完全互操作:

随着编辑们对该主题的深入了解,目标的范围可能会有所扩大。

1. 基础设施

本规范依赖于Infra[INFRA]

本规范中使用的一些术语在以下标准和规范中定义:


序列化一个整数,将其表示为最短的十进制数。

1.1. 写入

验证错误表示输入与有效输入不匹配。鼓励用户代理,尤其是合规性检查器,在某个地方报告它们。

验证错误并不意味着解析器终止。解析器的终止总是明确说明,例如,通过返回语句。

标记验证错误是有用的,因为错误处理可能不直观,遗留的用户代理可能未正确实现错误处理,所写内容的意图对其他开发者可能不清楚。

错误类型 错误描述 失败
IDNA
domain-to-ASCII

Unicode ToASCIICheckHyphensUseSTD3ASCIIRulesVerifyDnsLength 均设置为 true 时记录一个错误。[UTS46]

如果记录了关于 Unicode ToASCII 错误的详细信息,鼓励用户代理将其传递下去。

当 URL 是特殊的时,主机在处理前会被百分比解码,这会导致以下主机部分变为 “exa#mple.org”,从而触发此错误。

https://exa%23mple.org


(当 beStrict 为 true,或者 domain 不是 ASCII 字符串且使用宽松 参数的 Unicode ToASCII 也失败时)
主机解析
domain-percent-encoded

要作为域处理的输入的主机 包含一个 百分比编码字节

https://exam%70le.org

·
host-invalid-code-point

一个不透明主机(在一个 URL 中不是 特殊的)包含一个 被禁止的主机码点

foo://exa[mple.org

IPv4-empty-part

一个 IPv4 地址 以 U+002E (.) 结尾。

https://127.0.0.1./

·
IPv4-too-few-parts

一个 IPv4 地址 的部分少于 4 个。

https://1.2.3/

·
IPv4-too-many-parts

一个 IPv4 地址 的部分多于 4 个。

https://1.2.3.4.5/

IPv4-non-numeric-part

一个 IPv4 地址 部分不是数字。

https://test.42

IPv4-non-decimal-part

IPv4 地址 包含用十六进制或八进制数字表示的数值。

https://127.0.0x0.1

·
IPv4-out-of-range-part

一个 IPv4 地址 部分超过 255。

https://255.255.4000.1


(仅当适用于最后一个部分时)
IPv4-non-ASCII-input

一个 IPv4 地址 是通过 IDNA 处理从非 ASCII 字符串派生而来的。

https://①.②.③.④

·
IPv6-unclosed

一个 IPv6 地址 缺少 右方括号 U+005D (])。

https://[::1

IPv6-invalid-compression

一个 IPv6 地址 以不恰当的压缩开头。

https://[:1]

IPv6-too-many-pieces

一个 IPv6 地址 包含超过 8 个片段。

https://[1:2:3:4:5:6:7:8:9]

IPv6-multiple-compression

一个 IPv6 地址 在多个位置进行了压缩。

https://[1::1::1]

IPv6-invalid-code-point

一个 IPv6 地址 包含一个既不是 ASCII 十六进制数字 也不是 U+003A (:) 的码点。或者它意外结束。

https://[1:2:3!:4]

https://[1:2:3:]

IPv6-too-few-pieces

一个未压缩的 IPv6 地址包含少于 8 个片段。

https://[1:2:3]

IPv6-piece-leading-zero

一个 IPv6 地址 片段 包含前导 U+0030 (0)。

https://[::01]

·
IPv4-in-IPv6-too-many-pieces

一个带有 IPv4 地址语法的 IPv6 地址:该 IPv6 地址有超过 6 个片段。

https://[1:1:1:1:1:1:1:127.0.0.1]

IPv4-in-IPv6-invalid-code-point

一个带有 IPv4 地址语法的 IPv6 地址

  • 一个 IPv4 部分为空,或者包含非 ASCII 数字
  • 一个 IPv4 部分包含前导 0。
  • IPv4 部分过多。

https://[ffff::.0.0.1]

https://[ffff::127.0.xyz.1]

https://[ffff::127.0xyz]

https://[ffff::127.00.0.1]

https://[ffff::127.0.0.1.2]

IPv4-in-IPv6-out-of-range-part

一个带有 IPv4 地址语法的 IPv6 地址:一个 IPv4 部分超过 255。

https://[ffff::127.0.0.4000]

IPv4-in-IPv6-too-few-parts

一个带有 IPv4 地址语法的 IPv6 地址:一个 IPv4 地址包含 的部分过少。

https://[ffff::127.0.0]

URL 解析
invalid-URL-unit

发现了一个不是 URL 单元的码点。

https://example.org/>

https://example.org

ht
tps://example.org

https://example.org/%s

·
special-scheme-missing-following-solidus

输入的 scheme 后面没有跟着“//”。

file:c:/my-secret-folder

https:example.org

const url = new URL("https:foo.html", "https://example.org/");
·
missing-scheme-non-relative-URL

输入缺少一个 scheme,因为它不是以 ASCII 字母开头,并且要么未提供 base URL,要么该 base URL 不能 用作 base URL,因为它有一个不透明路径

输入的 scheme 缺失,且没有给出 base URL

const url = new URL("💩");

输入的 scheme 缺失,但该 base URL 有一个 不透明 路径

const url = new URL("💩", "mailto:[email protected]");
invalid-reverse-solidus

该 URL 具有特殊 scheme,并且它使用 U+005C (\) 而不是 U+002F (/)。

https://example.org\path\to\file

·
invalid-credentials

输入包含凭据

https://[email protected]

ssh://[email protected]

·
host-missing

输入具有特殊 scheme,但不包含主机

https://#fragment

https://:443

https://user:pass@

port-out-of-range

输入的端口过大。

https://example.org:70000

port-invalid

输入的端口无效。

https://example.org:7z

file-invalid-Windows-drive-letter

输入是一个relative-URL 字符串,它以 Windows 驱动器盘符开头, 并且 base URLscheme 是“file”。

const url = new URL("/c:/path/to/file", "file:///c:/");
·
file-invalid-Windows-drive-letter-host

一个 file: URL 的主机是 Windows 驱动器盘符。

file://c:

·

1.2. 解析器

EOF 代码点是一个概念性的代码点,表示字符串或代码点流的结束。

对于一个字符串输入指针是一个整数,指向输入中的代码点。最初它指向输入的开始。如果它为-1,则表示没有指向。如果它大于或等于输入代码点长度,则指向EOF代码点

当使用指针时,c引用指针指向的代码点,只要它没有指向空处。当指针指向空处时,c无法使用。

当使用指针时,remaining引用从指针+1到字符串末尾的代码点子串,只要c不是EOF代码点。当cEOF代码点时,remaining无法使用。

如果"mailto:username@example"是正在处理的字符串,并且指针指向@,c是U+0040 (@),而remaining是"example"。

如果正在处理的是空字符串,并且指针指向开始然后减1,使用cremaining将会出错。

1.3. 百分比编码字节

一个 百分号编码 字节 是一个由 U+0025 (%) 后跟两个 ASCII 十六进制数字组成的字符串。

通常,一个由 百分号编码字节组成的序列,最好满足这样的条件: 当它们被百分号解码后,再传给 无 BOM 的 UTF-8 解码或失败时,不会最终 变成失败。这一点有多重要, 取决于这些 百分号编码字节被用在哪里。例如,对于 host 解析器来说,不 遵循此建议是致命的;而对于 URL 渲染百分号编码 字节则不会以百分号解码后的形式被渲染。

百分比编码一个字节byte,返回由U+0025 (%),后跟表示byte的两个ASCII大写十六进制数字组成的字符串

百分比解码一个字节序列input,请按以下步骤操作:

input包含非ASCII字节时,使用除UTF-8解码,无BOM外的任何内容都可能不安全,不推荐使用。

  1. output为一个空的字节序列

  2. 对于input中的每个字节byte

    1. 如果byte不是0x25 (%),则将byte附加到output

    2. 否则,如果byte是0x25 (%),并且inputbyte之后的两个字节不在0x30 (0)到0x39 (9),0x41 (A)到0x46 (F),以及0x61 (a)到0x66 (f)的范围内,则将byte附加到output

    3. 否则:

      1. bytePointinputbyte之后的两个字节,解码后,解释为十六进制数。

      2. 将值为bytePoint的字节附加到output

      3. 跳过input中的下两个字节。

  3. 返回output

百分比解码一个标量值字符串input

  1. bytesinputUTF-8编码

  2. 返回bytes百分比解码结果。

通常,百分比编码会产生包含更多U+0025 (%)代码点的字符串,而百分比解码则会产生包含较少0x25 (%)字节的字节序列。


百分号编码集 是一个 集合,包含若干 码点

C0 控制百分号编码集 是一个 百分号编码集,包含 C0 控制字符及所有大于 U+007E (~) 的 码点

片段百分号编码集 是一个 百分号编码集,包含 C0 控制百分号编码集、U+0020 空格、U+0022 (")、U+003C (<)、U+003E (>) 以及 U+0060 (`)。

查询百分号编码集 是一个 百分号编码集,包含 C0 控制百分号编码集和 U+0020 空格、U+0022 (")、U+0023 (#)、U+003C (<)、U+003E (>)。

查询百分号编码集无法用 片段百分号编码集来定义,因为 U+0060 (`) 被省略了。

特殊查询百分号编码集 是一个 百分号编码集, 包含 查询 百分号编码集和 U+0027 (')。

路径百分号编码集 是一个 百分号编码集, 包含 查询百分号编码集及 U+003F (?)、U+005E (^)、U+0060 (`)、 U+007B ({) 和 U+007D (})。

用户信息百分号编码集 是一个 百分号编码集, 包含 路径百分号编码集和 U+002F (/)、U+003A (:)、U+003B (;)、U+003D (=)、U+0040 (@)、U+005B ([) 到 U+005D (])(含),以及 U+007C (|)。

组件 百分号编码集 是一个 百分号编码集, 包含 用户信息百分号编码集和 U+0024 ($) 到 U+0026 (&)(含)、U+002B (+) 以及 U+002C (,)。

这由 HTMLregisterProtocolHandler()使用, 也可以被其它标准采用, 百分号编码后的数据可以嵌入到 URL路径查询片段部分,或在 不透明主机名中。配合 UTF-8 百分号编码使用,结果与 JavaScript 的 encodeURIComponent() [sic] 完全一致。[HTML] [ECMA-262]

application/x-www-form-urlencoded 百分号编码集 是一个 百分号编码集, 包含 组件百分号编码集和 U+0021 (!)、 U+0027 (') 到 U+0029 右括号(含),以及 U+007E (~)。

application/x-www-form-urlencoded 百分号编码集包含了 除 ASCII 字母数字、U+002A (*)、U+002D (-)、U+002E (.) 和 U+005F (_) 以外的所有码点。

编码后百分号编码,需传入 编码 encoding标量值字符串 input,和 百分号编码集 percentEncodeSet

  1. 断言encodingUTF-8percentEncodeSet特殊查询百分号编码集application/x-www-form-urlencoded 百分号编码集

  2. 如果 percentEncodeSetapplication/x-www-form-urlencoded 百分号编码集,则令 spaceAsPlus 为 true,否则为 false。

  3. encoder 为从 encoding 获取的编码器结果。

  4. inputQueueinput 转换为 I/O 队列

  5. output 为空字符串。

  6. potentialError 为 0。

    需要非 null 值以进入随后 while 循环。

  7. potentialError 非 null 时:

    1. encodeOutput 为一个空的 I/O 队列

    2. 设置 potentialError 为以 编码或失败处理 inputQueueencoderencodeOutput 的结果。

    3. 对于 encodeOutput 转换为字节序列中的每个 byte

      1. 如果 spaceAsPlus 为 true 且 byte 为 0x20 (SP),则向 output 追加 U+002B (+),并 继续

      2. isomorph码点,其 byte

      3. 断言:percentEncodeSet 包含所有非 ASCII 码点

      4. isomorph 不在 percentEncodeSet 内,则追加 isomorphoutput

      5. 否则,百分号编码 byte,并将结果追加到 output

    4. 如果 potentialError 非 null,则向 output 追加 "%26%23", 再加上最短的 ASCII 数字序列,表示十进制下 potentialError,末尾追加 "%3B"。

      这通常出现在 encoding 不是 UTF-8 时。

  8. 返回 output

percentEncodeSet 可能取的值中,只有两个会对 U+0025 (%) 编码,因此可实现“可还原的数据”:组件 百分号编码集application/x-www-form-urlencoded 百分号编码集。其它值(常被URL 解析器 使用)不会处理 U+0025 (%),因此首先需对其做 UTF-8 百分号编码, 才能正确表示。

要对 标量值 scalarValuepercentEncodeSetUTF-8 百分号编码,返回以 编码后百分号编码配合 UTF-8scalarValue 作为 字符串,以及 percentEncodeSet 得到的结果。

要对 标量值字符串 inputpercentEncodeSetUTF-8 百分号编码,返回以 编码后百分号编码配合 UTF-8input 以及 percentEncodeSet 的结果。


以下是上文定义的操作的举例总结:

操作 输入 输出
百分号编码 input 0x23 "%23"
0x7F "%7F"
百分号解码 input `%25%s%1G` `%%s%1G`
字符串百分号解码 input "‽%25%2E" 0xE2 0x80 0xBD 0x25 0x2E
编码后百分号编码 使用 Shift_JISinput,和 特殊查询百分号编码集 " " "%20"
"" "%81%DF"
"" "%26%238253%3B"
编码后百分号编码 使用 ISO-2022-JPinput, 以及 特殊查询百分号编码集 "¥" "%1B(J\%1B(B"
编码后百分号编码 使用 Shift_JISinputapplication/x-www-form-urlencoded 百分号编码集 "1+1 ≡ 2%20‽" "1%2B1+%81%DF+2%2520%26%238253%3B"
UTF-8 百分号编码 input,使用 用户信息百分号编码集 U+2261 (≡) "%E2%89%A1"
U+203D (‽) "%E2%80%BD"
UTF-8 百分号编码 input 使用 用户信息百分号编码集 "Say what‽" "Say%20what%E2%80%BD"

2. 安全注意事项

URL的安全性取决于其环境。在呈现、解释和传递URL时需格外小心。

在呈现和分配新的URL时,需要考虑“欺骗”。这种攻击方式可能会让一个主机URL与另一个混淆。例如,考虑如何1/l/I、m/rn/rri、0/O和а/a看起来都非常相似。更糟糕的是,考虑U+202A LEFT-TO-RIGHT EMBEDDING以及类似的代码点是不可见的。[UTR36]

在将URLA传递给B时,双方都需要仔细考虑发生的情况。A可能会泄露它不希望泄露的数据。B可能会接收到意料之外的输入,并采取对用户有害的行动。尤其是,B永远不应信任A,因为在某些情况下,来自AURL可能来自不受信任的来源。

3. 主机 (域名和IP地址)

在高层次上,主机有效主机字符串主机解析器主机序列化器的关系如下:

根据提供给主机解析器isOpaque参数,解析-序列化往返操作会产生以下结果:

输入 输出 (isOpaque = false) 输出 (isOpaque = true)
EXAMPLE.COM example.com (域名) EXAMPLE.COM (不透明主机)
example%2Ecom example%2Ecom (不透明主机)
faß.example xn--fa-hia.example (域名) fa%C3%9F.example (不透明主机)
0 0.0.0.0 (IPv4) 0 (不透明主机)
%30 %30 (不透明主机)
0x 0x (不透明主机)
0xffffffff 255.255.255.255 (IPv4) 0xffffffff (不透明主机)
[0:0::1] [::1] (IPv6)
[0:0::1%5D] 失败
[0:0::%31]
09 失败 09 (不透明主机)
example.255 example.255 (不透明主机)
example^example 失败

3.1. 主机表示

主机是一个域名IP 地址不透明主机空主机。通常,主机用作网络地址,但有时在URL中用作不需要网络地址的不透明标识符。

典型的 URL主机不透明主机 的例子为 git://github.com/whatwg/url.git

下文引用的 RFC 仅供参考,对 主机 的编写、解析和序列化没有影响,除非在以下章节中另有说明。

域名是一个非空的ASCII 字符串,用于标识网络中的领域。[RFC1034]

域标签域名 domain 上通过 严格拆分 U+002E (.) 得到的结果。

example.comexample.com. 这两个域名并不相同,通常被视为不同的域名。

IP 地址是一个IPv4 地址IPv6 地址

一个 IPv4 地址是一个32 位无符号整数,用于标识网络地址。 [RFC791]

一个 IPv6 地址是一个128 位无符号整数,用于标识网络地址。该整数由 8 个 16 位无符号整数组成的列表构成,也称为 IPv6 地址片段[RFC4291]

<zone_id> 的支持是故意省略的

不透明主机是一个非空的ASCII 字符串,可以用于进一步处理。

空主机是一个空字符串。

3.2. 主机杂项

禁止的主机代码点是 U+0000 NULL, U+0009 TAB, U+000A LF, U+000D CR, U+0020 SPACE, U+0023 (#), U+002F (/), U+003A (:), U+003C (<), U+003E (>), U+003F (?), U+0040 (@), U+005B ([), U+005C (\), U+005D (]), U+005E (^), 或 U+007C (|)。

禁止的域名代码点禁止的主机代码点C0 控制、U+0025 (%) 或 U+007F DELETE。

要获取 主机 host公共后缀,请运行以下步骤。这些步骤返回 null 或表示 host 的一部分域名,该部分包含在公共后缀列表中。[PSL]

  1. 如果 host 不是域名,则返回 null。

  2. 如果 host.”结尾,则让 trailingDot 为“.”;否则为空字符串。

  3. 通过运行公共后缀列表算法,以 host 作为域名,确定 publicSuffix[PSL]

  4. 断言publicSuffix 是一个 ASCII 字符串, 并且 trailingDot 结尾。

  5. 返回 publicSuffix

要获取 主机 host可注册域名,请运行以下步骤。这些步骤返回 null 或由 host公共后缀及其前面的域标签(如果有)构成的域名

  1. 如果 host公共后缀为 null 或 host公共后缀等于 host,则返回 null。

  2. 如果 host.”结尾,则让 trailingDot 为“.”;否则为空字符串。

  3. 通过运行公共后缀列表算法,以 host 作为域名,确定 registrableDomain[PSL]

  4. 断言registrableDomain 是一个 ASCII 字符串, 并且 trailingDot 结尾。

  5. 返回 registrableDomain

主机输入 公共后缀 可注册域名
com com null
example.com com example.com
www.example.com com example.com
sub.www.example.com com example.com
EXAMPLE.COM com example.com
example.com. com. example.com.
github.io github.io null
whatwg.github.io github.io whatwg.github.io
إختبار xn--kgbechtv null
example.إختبار xn--kgbechtv example.xn--kgbechtv
sub.example.إختبار xn--kgbechtv example.xn--kgbechtv
[2001:0db8:85a3:0000:0000:8a2e:0370:7334] null null

规范应优先考虑概念进行安全决策。“公共后缀”和“可注册域名”的概念不能作为提供硬性安全边界的依据,因为公共后缀列表会因客户端而有所不同。忽略此建议的规范应仔细考虑是否应将 URL 的方案纳入任何决策中,即是否应使用 同一站点无方案同一站点的概念。

3.3. IDNA

domain 解析器算法,给定一个 标量值字符串 domain 和一个布尔值 beStrict,运行以下 步骤。它们返回失败或一个 domain

  1. strictResult 为使用 domain 和 true 运行 domain 解析器 ToASCII 的结果。

  2. 如果 strictResult 是失败值,则发生 domain-to-ASCII 验证 错误此步骤不会返回。

  3. 如果 beStrict 为 true:

    1. 如果 strictResult 是失败值,则返回失败。

    2. 返回 strictResult

  4. result 为 null。

  5. 如果 domain 是一个 ASCII 字符串,则将 result 设置为 domain小写化结果。

    beStrict 为 false 且 domain 是一个 ASCII 字符串时, 由于 Web 兼容性,无论 Unicode ToASCII 的结果如何,该算法都会返回 domain小写化结果。 IgnoreInvalidPunycode 本身并不足够,因为 Punycode 可以成功解码, 但仍然不满足有效性标准。例如,xn--8i7caa 解码为 www, 其码点的状态为“mapped”。[UTS46]

  6. 否则:

    1. result 设置为使用 domain 和 false 运行 domain 解析器 ToASCII 的结果。

    2. 如果 result 是失败值,则返回失败。

  7. 如果 result 是空字符串,则返回失败。

  8. 如果 result 包含一个 禁止的 domain 码点,则返回 失败。

    由于 Web 兼容性以及与非基于 DNS 的系统兼容, 禁止的 domain 码点UseSTD3ASCIIRules 为 true 时不允许的码点的一个子集。另见 issue #397

  9. 返回 result

本文档以及整个 Web 平台使用 Unicode IDNA Compatibility Processing,而不是 IDNA2008。例如, ☕.example 会变成 xn--53h.example,而不是失败。[UTS46] [RFC5890]

domain 解析器 ToASCII算法,给定一个 标量 值字符串 domain 和一个布尔值 beStrict,返回运行 Unicode ToASCII 的结果,其中 domain_name 设置为 domainCheckHyphens 设置为 beStrictCheckBidi 设置为 true,CheckJoiners 设置为 true,UseSTD3ASCIIRules 设置为 beStrictTransitional_Processing 设置为 false,VerifyDnsLength 设置为 beStrict,且 IgnoreInvalidPunycode 设置为 false。[UTS46]

domain 转 Unicode算法,给定一个 domain domain,运行以下步骤:

  1. result 为运行 Unicode ToUnicode 的结果,其中 domain_name 设置为 domainCheckHyphens 设置为 false,CheckBidi 设置为 true,CheckJoiners 设置为 true, UseSTD3ASCIIRules 设置为 false,Transitional_Processing 设置为 false,且 IgnoreInvalidPunycode 设置为 false。[UTS46]

  2. 如果记录了错误,则返回 domain

    因为 domain 只能由 host 解析器产生,所以任何已记录的 错误都已经表示为验证错误。返回 domain 可确保 domain 解析器domain 转 Unicode 在诸如 xn--8i7caa 这样的输入上能够往返转换。

  3. 返回 result

3.4. 主机编写

一个 有效主机字符串必须是一个有效域名字符串、一个 有效 IPv4 地址字符串,或者:U+005B ([),后跟一个 有效 IPv6 地址字符串,再后跟 U+005D (])。

一个字符串 input 是一个有效 域名,如果这些步骤返回 true:

  1. domain 为使用 input 和 true 运行域解析器的结果。

  2. 如果 domain 是失败,则返回 false。

  3. 如果在 domain 上运行以数字结尾检查器返回 true,则 返回 false。

  4. 返回 true。

理想情况下,我们根据组成一个 有效域的一系列码点来定义它,而不是通过 打地鼠式的方式: issue 245

有效域字符串必须是一个作为 有效域的字符串。

有效 IPv4 地址字符串必须是四个尽可能短的 ASCII 数字字符串,表示 0 到 255 范围内的十进制数, 包含端点,彼此之间由 U+002E (.) 分隔。

有效 IPv6 地址字符串必须是下列之一:

有效 IPv6 片段和 IPv4 字符串是一个有效 IPv6 片段字符串, 后跟 U+003A (:),再后跟一个有效 IPv4 地址字符串;或者单独一个 有效 IPv4 地址字符串

有效 IPv6 片段 字符串是一个或多个有效 IPv6 片段字符串,彼此之间由 U+003A (:) 分隔。

有效 IPv6 片段 字符串是一个尽可能短的 ASCII 十六进制 数字字符串, 表示 0 到 0xFFFF 范围内的十六进制数,包含端点。

一个有效 IPv6 片段字符串有效片段 长度是它所包含的 有效 IPv6 片段字符串的数量。一个 有效 IPv6 片段和 IPv4 字符串有效片段长度是它 所包含的有效 IPv6 片段字符串的数量, 再加 2。

这是从 A Recommendation for IPv6 Address Text Representation 派生而来的。为了与 IPv4 保持一致, 不允许前导零。[RFC5952]

有效不透明主机 字符串必须是下列之一:

这不是有效主机字符串定义的一部分,因为它需要上下文 才能区分。

3.5. 主机解析

主机解析器接受一个 标量值字符串 input,以及一个可选布尔值 isOpaque(默认为 false),然后运行这些步骤。它们返回失败或一个主机

  1. 如果 input 以 U+005B ([) 开头,则:

    1. 如果 input 不是以 U+005D (]) 结尾,IPv6-unclosed 验证错误,返回失败。

    2. 返回对移除其前导 U+005B ([) 和尾随 U+005D (]) 后的 input 进行 IPv6 解析的结果。

  2. 如果 isOpaque 为 true,则返回对 input 进行 不透明主机解析的结果。

  3. 断言:input 不是空字符串。

  4. 如果 input 包含百分比编码字节domain-percent-encoded 验证错误

  5. domain 为在 input百分比解码上运行 无 BOM 的 UTF-8 解码的结果。

    或者也可以使用无 BOM 的 UTF-8 解码或失败, 并结合在失败时提前返回,因为域解析器会在 U+FFFD (�) 上失败。

  6. asciiDomain 为使用 domain 和 false 运行 域解析器的结果。

  7. 如果 asciiDomain 为失败,则返回失败。

  8. 如果 asciiDomain 以数字结尾

    1. 如果 domain 不是ASCII 字符串IPv4-non-ASCII-input 验证错误

    2. 返回对 asciiDomain 进行 IPv4 解析的结果。

  9. 返回 asciiDomain


以数字结尾 检查器接受一个ASCII 字符串 input,然后 运行这些步骤。它们返回一个布尔值。

  1. 断言:input 不是空字符串。

  2. parts 为在 U+002E (.) 上严格 拆分 input 的结果。

  3. 如果 parts 中的最后一个项目是空字符串,则从 parts移除最后一个项目

  4. lastparts 中的最后一个项目

  5. 如果 last 不是空字符串,并且只包含 ASCII 数字,则返回 true。

    错误输入“09”会在之后阶段被 IPv4 解析器捕获。

  6. 如果将 last 作为 IPv4 数字解析不返回 失败,则返回 true。

    这等同于检查 last 是否为“0X” 或 “0x”,后跟零个或多个 ASCII 十六进制数字

  7. 返回 false。

IPv4 解析器 接受一个ASCII 字符串 input ,然后运行这些步骤。它们返回失败或一个 IPv4 地址

IPv4 解析器不应被直接调用。相反,应检查 主机解析器的返回值是否为一个 IPv4 地址

  1. parts 为在 U+002E (.) 上严格 拆分 input 的结果。

  2. 如果 parts 中的最后一个项目是空字符串,则:

    1. IPv4-empty-part 验证错误

    2. 如果 parts大小 大于 1,则从 parts移除 最后一个项目

  3. 如果 parts大小小于 4,IPv4-too-few-parts 验证 错误

  4. 如果 parts大小大于 4,IPv4-too-many-parts 验证 错误,返回失败。

  5. numbers 为空列表

  6. parts 的每个 part 执行

    1. result解析 part 的结果。

    2. 如果 result 为失败,IPv4-non-numeric-part 验证错误, 返回失败。

    3. 如果 result[1] 为 true,IPv4-non-decimal-part 验证错误

    4. result[0] 追加numbers

  7. 如果 numbers 中的任何项目大于 255,IPv4-out-of-range-part 验证 错误

  8. 如果 numbers 中除最后一个项目外的任何项目大于 255,则 返回失败。

  9. 如果 numbers 中的最后一个项目大于或等于 256(5 − numbers大小), 则返回失败。

  10. ipv4numbers 中的最后一个项目

  11. numbers移除最后一个项目

  12. counter 为 0。

  13. numbers 的每个 n 执行

    1. ipv4 增加 n × 256(3 − counter)

    2. counter 增加 1。

  14. 返回 ipv4

IPv4 数字 解析器接受一个ASCII 字符串 input,然后运行 这些步骤。它们返回失败或一个由数字和布尔值组成的元组

  1. 如果 input 是空字符串,则返回失败。

  2. validationError 为 false。

  3. R 为 10。

  4. 如果 input 包含至少两个码点,且前两个码点是 “0X”或“0x”,则:

    1. validationError 设为 true。

    2. input 中移除前两个码点。

    3. R 设为 16。

  5. 否则,如果 input 包含至少两个码点,且第一个码点是 U+0030 (0),则:

    1. validationError 设为 true。

    2. input 中移除第一个码点。

    3. R 设为 8。

  6. 如果 input 是空字符串,则返回 (0, true)。

  7. 如果 input 包含不是 radix-R 数字的码点,则 返回失败。

  8. outputinput 以 radix-R 记法表示的数学整数值, 其中对值为 0 到 15 的数字使用 ASCII 十六进制数字

  9. 返回 (output, validationError)。


IPv6 解析器 接受一个标量值字符串 input,然后运行这些步骤。它们返回失败或一个 IPv6 地址

从理论上讲,IPv6 解析器可以被直接调用,但实际这样做之前请先与 本文档的编辑讨论。

  1. address 为一个新的 IPv6 地址,其片段 全部为 0。

  2. pieceIndex 为 0。

  3. compress 为 null。

  4. pointerinput 的一个指针

  5. 如果 c 是 U+003A (:),则:

    1. 如果 remaining 不是 以 U+003A (:) 开头,IPv6-invalid-compression 验证错误,返回失败。

    2. pointer 增加 2。

    3. pieceIndex 增加 1,然后将 compress 设为 pieceIndex

  6. c 不是 EOF 码点时:

    1. 如果 pieceIndex 为 8,IPv6-too-many-pieces 验证错误, 返回失败。

    2. 如果 c 是 U+003A (:),则:

      1. 如果 compress 非 null,IPv6-multiple-compression 验证错误,返回失败。

      2. pointerpieceIndex 增加 1,将 compress 设为 pieceIndex,然后继续
    3. valuelength 为 0。

    4. length 小于 4 且 cASCII 十六进制数字时,将 value 设为 value × 0x10 + 被解释为十六进制数的 c, 并将 pointerlength 增加 1。

    5. 如果 c 是 U+002E (.),则:

      1. 如果 length 为 0,IPv4-in-IPv6-invalid-code-point 验证错误,返回失败。

      2. pointer 减少 length

      3. 如果 pieceIndex 大于 6,IPv4-in-IPv6-too-many-pieces 验证错误,返回失败。

      4. numbersSeen 为 0。

      5. c 不是 EOF 码点时:

        1. ipv4Piece 为 null。

        2. 如果 numbersSeen 大于 0,则:

          1. 如果 c 是 U+002E (.) 且 numbersSeen 小于 4,则将 pointer 增加 1。

          2. 否则,IPv4-in-IPv6-invalid-code-point 验证错误,返回 失败。
        3. 如果 c 不是 ASCII 数字IPv4-in-IPv6-invalid-code-point 验证错误,返回 失败。

        4. cASCII 数字时:

          1. number 为被解释为十进制数的 c

          2. 如果 ipv4Piece 为 null,则将 ipv4Piece 设为 number

          3. 否则,如果 ipv4Piece 为 0,IPv4-in-IPv6-invalid-code-point 验证错误,返回 失败。

          4. 否则,将 ipv4Piece 设为 ipv4Piece × 10 + number

          5. 如果 ipv4Piece 大于 255,IPv4-in-IPv6-out-of-range-part 验证错误,返回 失败。

          6. pointer 增加 1。

        5. address[pieceIndex] 设为 address[pieceIndex] × 0x100 + ipv4Piece

        6. numbersSeen 增加 1。

        7. 如果 numbersSeen 为 2 或 4,则将 pieceIndex 增加 1。

      6. 如果 numbersSeen 不是 4,IPv4-in-IPv6-too-few-parts 验证错误,返回失败。

      7. 跳出

    6. 否则,如果 c 是 U+003A (:):

      1. pointer 增加 1。

      2. 如果 cEOF 码点IPv6-invalid-code-point 验证错误,返回失败。

    7. 否则,如果 c 不是 EOF 码点IPv6-invalid-code-point 验证错误,返回失败。

    8. 如果 length 大于 1 且 value 小于 0x10length − 1IPv6-piece-leading-zero 验证 错误

    9. address[pieceIndex] 设为 value

    10. pieceIndex 增加 1。

  7. 如果 compress 非 null,则:

    1. swapspieceIndexcompress

    2. pieceIndex 设为 7。

    3. pieceIndex 不是 0 且 swaps 大于 0 时,交换 address[pieceIndex] 与 address[compress + swaps − 1],然后将 pieceIndexswaps 都减少 1。

  8. 否则,如果 compress 为 null 且 pieceIndex 不是 8, IPv6-too-few-pieces 验证错误,返回 失败。

  9. 返回 address


不透明主机 解析器接受一个 标量值字符串 input,然后运行这些 步骤。它们返回失败或一个 不透明主机

  1. 如果 input 包含被禁止的主机码点host-invalid-code-point 验证错误,返回 失败。

  2. 如果 input 包含一个既不是 码点 URL 码点也不是 U+0025 (%) 的码点,invalid-URL-unit 验证错误

  3. 如果 input 包含一个 U+0025 (%),且其后的两个码点 不是 ASCII 十六进制数字invalid-URL-unit 验证 错误

  4. 返回在 input 上使用 C0 控制百分比编码集运行 UTF-8 百分比编码的结果。

3.6. 主机序列化

主机 序列化器接受一个 主机 host,然后 运行这些步骤。它们返回一个 ASCII 字符串

  1. 如果 host 是一个 IPv4 地址,则返回在 host 上运行 IPv4 序列化器的结果。

  2. 否则,如果 host 是一个 IPv6 地址,则返回 U+005B ([),后跟在 host 上运行 IPv6 序列化器的结果,再后跟 U+005D (])。

  3. 否则,host 是一个不透明主机,或空主机, 返回 host

IPv4 序列化器接受一个 IPv4 地址 address,然后运行这些步骤。它们返回一个 ASCII 字符串

  1. output 为空字符串。

  2. naddress 的值。

  3. 对范围 1 到 4(含两端)中的每个 i 执行

    1. n % 256 序列化后的结果前置到 output

    2. 如果 i 不是 4,则将 U+002E (.) 前置到 output

    3. n 设为 floor(n / 256)。

  4. 返回 output

IPv6 序列化器接受一个 IPv6 地址 address,然后运行这些步骤。它们返回一个 ASCII 字符串

  1. output 为空字符串。

  2. compress 为给定 address查找 IPv6 地址 压缩片段索引的结果。

  3. ignore0 为 false。

  4. address片段索引中的每个 pieceIndex 执行

    1. 如果 ignore0 为 true 且 address[pieceIndex] 为 0,则 继续

    2. 否则,如果 ignore0 为 true,则将 ignore0 设为 false。

    3. 如果 compresspieceIndex,则:

      1. 如果 pieceIndex 为 0,则令 separator 为“::”; 否则为 U+003A (:)。

      2. separator 追加到 output

      3. ignore0 设为 true,并继续

    4. address[pieceIndex] 以尽可能短的小写十六进制数表示, 并追加到 output

    5. 如果 pieceIndex 不是 7,则将 U+003A (:) 追加到 output

  5. 返回 output

此算法要求采用 A Recommendation for IPv6 Address Text Representation 中的建议。 [RFC5952]

要在给定一个 IPv6 地址 address 的情况下查找 IPv6 地址压缩片段索引

  1. longestIndex 为 null。

  2. longestSize 为 1。

  3. foundIndex 为 null。

  4. foundSize 为 0。

  5. 对于 address片段索引中的每个 pieceIndex 执行

    1. 如果 address片段[pieceIndex] 不是 0:

      1. 如果 foundSize 大于 longestSize,则将 longestIndex 设为 foundIndex,并将 longestSize 设为 foundSize

      2. foundIndex 设为 null。
      3. foundSize 设为 0。
    2. 否则:

      1. 如果 foundIndex 为 null,则将 foundIndex 设为 pieceIndex

      2. foundSize 增加 1。

  6. 如果 foundSize 大于 longestSize,则返回 foundIndex

  7. 返回 longestIndex

0:f:0:0:f:f:0:0 中,它会指向第二个 0。

3.7. 主机等效性

要确定主机A是否等于主机B,如果AB,则返回true,否则返回false。

证书比较需要一个忽略域名末尾点(如果有的话)的主机等效性检查。然而,这些主机还强制执行了诸如DNS长度等其他方面的验证,而这些在此处未强制执行,因为URL不强制执行它们。如果有人对如何将这两者更紧密结合,或什么是好的统一模型有好的建议,请提交问题。

4. URL

从高层来看,一个 URL有效 URL 字符串URL 解析器URL 序列化器之间的关系如下:

输入 基准 有效 输出
https:example.org https://example.org/
https://////example.com/// https://example.com///
https://example.com/././foo https://example.com/foo
hello:world https://example.com/ hello:world
https:example.org https://example.com/ https://example.com/example.org
\example\..\demo/.\ https://example.com/ https://example.com/demo/
example https://example.com/demo https://example.com/example
file:///C|/demo file:///C:/demo
.. file:///C:/demo file:///C:/
file://localhost/ file:///
file://loc%61lhost/ file:///
https://user:[email protected]/ https://user:[email protected]/
https://example.org/foo bar https://example.org/foo%20bar
https://EXAMPLE.com/../x https://example.com/x
https://ex ample.org/ 失败
example ❌,由于缺少基准 失败
https://example.com:demo 失败
http://[www.example.com]/ 失败
https://example.org// https://example.org//
https://example.com/[]?[]#[] https://example.com/[]?[]#[]
https://example/%?%#% https://example/%?%#%
https://example/%25?%25#%25 https://example/%25?%25#%25

为简洁起见,基准和输出 URL 均以 序列化形式表示。

4.1. URL 表示

一个 URL 是一个结构体,它 表示一个通用标识符。为与有效 URL 字符串区分开来,它也可以 被称为 URL 记录

一个 URLscheme 是一个 ASCII 字符串,用于标识 URL 的类型,并可在解析后用于 分派一个 URL 以进行进一步 处理。 它最初是空字符串。

一个 URLusername 是一个 ASCII 字符串,用于标识用户名。它最初是空字符串。

一个 URLpassword 是一个 ASCII 字符串,用于标识密码。它最初是空字符串。

一个 URLhost 是 null 或一个 主机。它最初为 null。

下表列出了允许的 URLscheme / host 组合。

scheme host
IPv4 地址 IPv6 地址 不透明主机 空主机 null
除 "file" 外的特殊 scheme
"file"
其他

一个 URLport 是 null 或一个 16 位无符号整数,用于标识一个网络端口。它 最初为 null。

一个 URLpath 是一个 URL 路径,通常用于标识一个 位置。它最初是 « »。

一个特殊的 URLpath 始终是一个 列表,即它 从不是不透明的

一个 URLquery 要么是 null,要么是一个 ASCII 字符串。它最初为 null。

一个 URLfragment 要么是 null,要么是 一个 ASCII 字符串,可用于对该 URL 的其他组件所标识的资源进行进一步处理。 它最初为 null。

一个 URL 还具有关联的 blob URL 条目,它要么是 null,要么是一个 blob URL 条目。它最初为 null。

这用于支持缓存一个 "blob" URL 所引用的对象及其 源。缓存这些内容很重要,因为在解析与获取之间,该 URL 可能会从 blob URL 存储中移除,而获取仍然 需要成功。

下表列出了有效 URL 字符串在被解析时如何映射 到一个 URL 的组件。Usernamepasswordblob URL 条目被省略;在下面的示例中,它们分别是空字符串、 空字符串和 null。

输入 Scheme Host Port Path Query Fragment
https://example.com/ "https" "example.com" null « 空字符串 » null null
https://localhost:8000/search?q=text#hello "https" "localhost" 8000 « "search" » "q=text" "hello"
urn:isbn:9780307476463 "urn" null null "isbn:9780307476463" null null
file:///ada/Analytical%20Engine/README.md "file" 空字符串 null « "ada", "Analytical%20Engine", "README.md" » null null

URL 路径要么是一个 URL 路径片段,要么是一个由零个 或多个 URL 路径 片段组成的列表

URL 路径片段是一个 ASCII 字符串。它通常指代一个 目录或文件,但没有预定义含义。

一个 单点 URL 路径片段 是一个 URL 路径片段, 它是 ".",或者是与 "%2e" ASCII 大小写不敏感 匹配的字符串。

一个 双点 URL 路径片段 是一个 URL 路径片段, 它是 "..",或者是与 ".%2e"、"%2e." 或 "%2e%2e" ASCII 大小写不敏感 匹配的字符串。

4.2. URL 杂项

特殊 scheme 是一个ASCII 字符串,它列在下表第一列中。 特殊 scheme默认端口列在 同一行的第二列中。任何其他 默认端口 ASCII 字符串 是 null。

特殊方案 默认端口
"ftp" 21
"file" null
"http" 80
"https" 443
"ws" 80
"wss" 443

URL 是特殊的,如果它的方案特殊方案URL不是特殊的,如果它的方案不是特殊方案

URL包含凭证,如果它的用户名密码不是空字符串。

URL具有不透明路径,如果它的路径URL路径段

URL如果其主机为null或为空字符串,或者其方案是"file" ,则不能具有用户名/密码/端口

URL可以被指定为基础URL

基础URL对于URL解析器很有用,当输入可能是相对URL字符串时。


Windows 驱动器号 是两个码点,第一个是 ASCII 字母,第二个是 U+003A (:) 或 U+007C (|)。

规范化的 Windows 驱动器号Windows 驱动器号,其中第二个码点是 U+003A (:)。

根据 URL 写入 部分,只有 规范化的 Windows 驱动器号 是合规的。

如果符合以下所有条件,则字符串 以 Windows 驱动器号开头

字符串 以 Windows 驱动器号开头
"c:"
"c:/"
"c:a"

缩短 url 的路径

  1. 断言url 没有不透明路径

  2. pathurl路径

  3. 如果 url方案是 "file",path大小为1,并且 path[0] 是规范化的 Windows 驱动器号,则返回。

  4. 移除 path 的最后一项(如果有)。

4.3. URL 写入

有效 URL 字符串必须是带片段的相对 URL 字符串带片段的绝对 URL 字符串

带片段的绝对 URL 字符串必须是 一个绝对 URL 字符串,可选地后跟 U+0023 (#) 和一个URL 片段字符串

绝对 URL 字符串必须是以下之一:

以上任一项都可选择后跟 U+003F (?) 和一个URL-查询字符串

一个URL-方案字符串必须是一个ASCII 字母, 后跟零个或多个ASCII 字母数字、U+002B (+)、U+002D (-) 和 U+002E (.)。 方案应被 注册在 IANA URI [sic] Schemes 注册表中。 [IANA-URI-SCHEMES] [RFC7595]

一个带片段的相对 URL 字符串 必须是 U+0023 (#) 后跟一个URL-片段字符串,如果基 URL具有 不透明路径;否则,为一个 相对 URL 字符串,可选择后跟 U+0023 (#) 和一个URL-片段 字符串

一个相对 URL 字符串必须是:

以上任一项都可选择后跟 U+003F (?) 和一个URL-查询字符串

解析 带片段的相对 URL 字符串时,需要一个非 null 的基 URL

一个方案相对特殊 URL 字符串必须是 "//",后跟一个 有效主机字符串, 可选择后跟 U+003A (:) 和一个URL-端口字符串,可选择 后跟一个路径绝对 URL 字符串

一个URL-端口字符串必须是以下之一:

一个方案相对 URL 字符串必须是 "//",后跟一个不透明主机和端口字符串,可选择后跟一个 路径绝对 URL 字符串

一个不透明主机和端口字符串必须为空字符串,或者是:一个 有效 不透明主机字符串,可选择后跟 U+003A (:) 和一个URL-端口字符串

一个方案相对 file URL 字符串 必须 是 "//",可选择后跟以下之一:

一个路径绝对 URL 字符串必须是 U+002F (/), 后跟零个或多个URL-路径段字符串,彼此之间以 U+002F (/) 分隔。

一个路径绝对非授权 URL 字符串必须是一个路径绝对 URL 字符串, 且不以两个 U+002F (/) 码位开始。

一个路径相对 URL 字符串必须是零个 或多个 URL-路径段字符串,彼此之间以 U+002F (/) 分隔,且不以 U+002F (/) 开始。

一个 无方案路径相对 URL 字符串 必须是一个路径相对 URL 字符串,且不以下列内容开始:一个URL-方案字符串, 后跟 U+003A (:)。

一个不透明路径 URL 字符串必须是零个或多个URL 单元,不包括 U+003F (?),其中第一个(如果有)不是 U+002F (/)。

一个URL-路径段字符串必须是 以下之一:

一个URL-查询字符串必须是零个或多个URL 单元

一个URL-片段字符串必须是零个或多个 URL 单元

URL 码点ASCII 字母数字、 U+0021 (!)、 U+0024 ($)、 U+0026 (&)、 U+0027 (')、 U+0028 左括号、 U+0029 右括号、 U+002A (*)、 U+002B (+)、 U+002C (,)、 U+002D (-)、 U+002E (.)、 U+002F (/)、 U+003A (:)、 U+003B (;)、 U+003D (=)、 U+003F (?)、 U+0040 (@)、 U+005F (_)、 U+007E (~), 以及范围 U+00A0 到 U+10FFFD(含)内的码 点,但不包括代理项非字符

大于 U+007F DELETE 的码点将由URL 解析器转换为 百分号编码 字节

在 HTML 中,当文档编码是遗留编码时, URL 查询字符串中 高于 U+007F DELETE 的码点将会 使用文档的编码转换为 百分号编码 字节。这 可能导致一个 URL 在一个文档中可用,但复制到另一个使用 不同文档编码的文档中时出现问题。处处使用 UTF-8 编码可以解决 这个问题。

例如,考虑此 HTML 文档:

<!doctype html>
<meta charset="windows-1252">
<a href="?sm&ouml;rg&aring;sbord">Test</a>

由于文档编码是 windows-1252,该链接的URL查询 将是 "sm%F6rg%E5sbord"。如果文档编码曾是 UTF-8,则它会改为 "sm%C3%B6rg%C3%A5sbord"。

URL 单元URL 码点百分号编码 字节

百分号编码字节可用于编码不是 URL 码点或被排除而不能写入的 码点。


无法在一个有效 URL 字符串中表达 一个用户名密码,它们属于 URL 记录

4.4. URL 解析

URL 解析器 接受一个 标量值字符串 input,带有一个可选的 null 或基 URL base(默认为 null)以及一个可选的编码 encoding(默认为 UTF-8), 然后运行以下步骤:

非 Web 浏览器实现只需要实现基本 URL 解析器

Web 浏览器地址栏中的用户输入如何转换为 URL 记录,不在 本标准范围内。本标准确实包括 URL 渲染要求,因为它们与信任决策相关。

  1. url 为在 input 上运行基本 URL 解析器 并带上 baseencoding 的结果。

  2. 如果 url 是 failure,返回 failure。

  3. 如果 url方案不是 "blob",返回 url

  4. urlblob URL 条目设为 解析 blob URL url 的结果,如果其没有返回 failure;否则设为 null。

  5. 返回 url


基本 URL 解析器接受一个 标量值字符串 input,带有一个可选的 null 或基 URL base(默认为 null),一个可选的编码 encoding(默认为 UTF-8), 一个可选的URL url, 以及一个可选的状态覆盖 state override, 然后运行以下步骤:

encoding 参数是一个仅与 HTML 相关的遗留概念。 urlstate override 参数仅供各种 API 使用。[HTML]

当没有传入 urlstate override 参数时, 基本 URL 解析器返回一个新的URL或 failure。如果传入了它们, 该算法会修改传入的 url,并且可以在不返回任何内容的情况下终止。

  1. 如果没有给定 url

    1. url 设为一个新的URL

    2. 如果 input 包含任何前导或尾随的C0 控制符或空格invalid-URL-unit 验证错误

    3. input 中移除任何前导和尾随的C0 控制符或空格

  2. 如果 input 包含任何ASCII 制表符或换行符invalid-URL-unit 验证 错误

  3. input 中移除所有ASCII 制表符或换行符

  4. statestate override, 如果给定;否则为方案开始状态

  5. encoding 设为从 encoding 获取输出编码的结果。

  6. buffer 为空字符串。

  7. atSignSeeninsideBracketspasswordTokenSeen 为 false。

  8. pointerinput 的一个指针

  9. 通过对 state 进行分支来持续运行以下状态机。如果一次运行之后 pointer 指向EOF 码位,转到下一步。否则,将 pointer 增加 1,并继续状态机。

    方案开始状态
    1. 如果 c 是一个ASCII 字母, 将c小写化形式附加到 buffer,并 将 state 设为方案状态

    2. 否则,如果没有给定 state override,则将 state 设为 无 方案状态,并将 pointer 减少 1。

    3. 否则,返回 failure。

      此 failure 指示专门由 Location 对象的 protocol setter 使用。

    方案状态
    1. 如果 c 是一个ASCII 字母数字、U+002B (+)、U+002D (-) 或 U+002E (.), 将c小写化形式附加到 buffer

    2. 否则,如果 c 是 U+003A (:),则:

      1. 如果给定了 state override,则:

        1. 如果 url方案是一个特殊方案,且 buffer 不是一个特殊 方案,则返回。

        2. 如果 url方案不是一个特殊方案,且 buffer 是一个特殊 方案,则返回。

        3. 如果 url 包含凭据 或具有非 null 的端口, 且 buffer 是 "file",则返回。

        4. 如果 url方案是 "file",且其 主机空主机,则返回。

      2. url方案设为 buffer

      3. 如果给定了 state override,则:

        1. 如果 url端口url方案默认端口,则将 url端口设为 null。

        2. 返回。

      4. buffer 设为空字符串。

      5. 如果 url方案是 "file", 则:

        1. 如果剩余部分不是以 "//" 开头, special-scheme-missing-following-solidus 验证错误

        2. state 设为file 状态

      6. 否则,如果 url 是特殊的base 为 非 null,且 base方案url方案相同:

        1. 断言base 是特殊的(因此不具有 不透明路径)。

        2. state 设为特殊 相对或授权状态

      7. 否则,如果 url 是特殊的,将 state 设为 特殊授权 斜杠状态

      8. 否则,如果剩余部分以一个 U+002F (/) 开头,将 state 设为 路径或授权状态,并 将 pointer 增加 1。

      9. 否则,将 url路径设为 空字符串,并将 state 设为不透明路径状态

    3. 否则,如果没有给定 state override,将 buffer 设为空字符串,将 state 设为 无 方案状态,并重新开始(从 input 中的第一个码位 开始)。

    4. 否则,返回 failure。

      此 failure 指示专门由 Location 对象的 protocol setter 使用。此外,此状态中较早出现的非 failure 终止, 是为了定义该 setter 而有意设置的差异。

    无方案状态
    1. 如果 base 为 null,或者 base 具有不透明路径c 不是 U+0023 (#),则产生missing-scheme-non-relative-URL 验证错误, 返回 failure。

    2. 否则,如果 base 具有不透明路径c 是 U+0023 (#),则将 url方案设为 base方案, 将 url路径设为 base路径, 将 url查询设为 base查询, 将 url片段设为空字符串,并将 state 设为 片段状态

    3. 否则,如果 base方案 不是 "file",则将 state 设为相对状态,并将 pointer 减少 1。

    4. 否则,将 state 设为file 状态,并将 pointer 减少 1。

    特殊相对或授权状态
    1. 如果 c 是 U+002F (/) 且剩余部分 以 U+002F (/) 开头,则将 state 设为特殊授权忽略 斜杠状态,并将 pointer 增加 1。

    2. 否则,产生special-scheme-missing-following-solidus 验证错误,将 state 设为相对状态,并将 pointer 减少 1。

    路径或授权状态
    1. 如果 c 是 U+002F (/),则 将 state 设为授权状态

    2. 否则,将 state 设为路径状态,并将 pointer 减少 1。

    相对状态
    1. 断言:base方案不是 "file"。

    2. url方案设为 base方案

    3. 如果 c 是 U+002F (/),则 将 state 设为相对斜杠状态

    4. 否则,如果 url 是特殊的c 是 U+005C (\), invalid-reverse-solidus 验证错误,将 state 设为 相对斜杠状态

    5. 否则:

      1. url用户名设为 base用户名, 将 url密码设为 base密码, 将 url主机设为 base主机, 将 url端口设为 base端口, 将 url路径设为 base路径的一个克隆,并将 url查询设为 base查询

      2. 如果 c 是 U+003F (?),则将 url查询 设为空 字符串,并将 state 设为查询状态

      3. 否则,如果 c 是 U+0023 (#),则将 url片段设为 空字符串,并将 state 设为片段 状态

      4. 否则,如果 c 不是 EOF 码位

        1. url查询设为 null。

        2. 缩短 url路径

        3. state 设为路径状态, 并将 pointer 减少 1。

    相对斜杠状态
    1. 如果 url 是特殊的,且 c 是 U+002F (/) 或 U+005C (\),则:

      1. 如果 c 是 U+005C (\),产生invalid-reverse-solidus 验证错误

      2. state 设为特殊 授权忽略斜杠状态

    2. 否则,如果 c 是 U+002F (/),则将 state 设为 授权状态

    3. 否则,将 url用户名设为 base用户名, 将 url密码设为 base密码, 将 url主机设为 base主机, 将 url端口设为 base端口, 将 state 设为路径状态,然后将 pointer 减少 1。

    特殊授权斜杠状态
    1. 如果 c 是 U+002F (/) 且剩余部分 以 U+002F (/) 开头,则将 state 设为特殊授权 忽略斜杠状态,并将 pointer 增加 1。

    2. 否则,产生special-scheme-missing-following-solidus 验证错误,将 state 设为特殊授权 忽略斜杠状态,并将 pointer 减少 1。

    特殊权限忽略斜杠状态
    1. 如果 c 既不是 U+002F (/) 也不是 U+005C (\),则将 state 设为 权限状态,并将 pointer 减少 1。

    2. 否则,special-scheme-missing-following-solidus 验证错误

    权限状态
    1. 如果 c 是 U+0040 (@),则:

      1. Invalid-credentials 验证错误

      2. 如果 atSignSeen 为 true,则将 "%40" 前置到 buffer

      3. atSignSeen 设为 true。

      4. buffer 中的每个 codePoint

        1. 如果 codePoint 是 U+003A (:) 且 passwordTokenSeen 为 false, 则将 passwordTokenSeen 设为 true,并继续

        2. encodedCodePoints 为使用 userinfo 百分比编码集codePoint 运行 UTF-8 百分比编码 的结果。

        3. 如果 passwordTokenSeen 为 true,则将 encodedCodePoints 追加到 urlpassword

        4. 否则,将 encodedCodePoints 追加到 urlusername

      5. buffer 设为空字符串。

    2. 否则,如果以下之一为 true:

      则:

      1. 如果 atSignSeen 为 true 且 buffer 是空 字符串, host-missing 验证 错误,返回失败。

      2. pointer 减少 buffer码点长度 + 1, 将 buffer 设为空字符串,并将 state 设为 主机状态

    3. 否则,将 c 追加到 buffer

    主机状态
    主机名状态
    1. 如果给定了 state override,且 urlscheme 是 "file",则将 pointer 减少 1,并将 state 设为 文件主机状态

    2. 否则,如果 c 是 U+003A (:),且 insideBrackets 为 false:

      1. 如果 buffer 是空字符串,host-missing 验证错误, 返回失败。

      2. 如果给定了 state override,且 state override主机名状态,则返回失败。

      3. host 为使用 url 不是特殊的,对 buffer 进行主机 解析的结果。

      4. 如果 host 为失败,则返回失败。

      5. urlhost 设为 host,将 buffer 设为空字符串, 并将 state 设为 端口状态

    3. 否则,如果以下之一为 true:

      则将 pointer 减少 1,然后:

      1. 如果 url 是特殊的,且 buffer 是 空字符串, host-missing 验证 错误,返回失败。

      2. 否则,如果给定了 state overridebuffer 是 空字符串,并且要么 url 包含凭据,要么 urlport 非 null,则返回 失败。

      3. host 为使用 url 不是特殊的,对 buffer 进行主机 解析的结果。

      4. 如果 host 为失败,则返回失败。

      5. urlhost 设为 host,将 buffer 设为空字符串, 并将 state 设为 路径开始状态

      6. 如果给定了 state override,则返回。

    4. 否则:

      1. 如果 c 是 U+005B ([),则将 insideBrackets 设为 true。

      2. 如果 c 是 U+005D (]),则将 insideBrackets 设为 false。

      3. c 追加到 buffer

    端口状态
    1. 如果 c 是一个 ASCII 数字,则将 c 追加到 buffer

    2. 否则,如果以下之一为 true:

      • cEOF 码点、U+002F (/)、U+003F (?) 或 U+0023 (#);

      • url 是特殊的,且 c 是 U+005C (\);或

      • 给定了 state override

      则:

      1. 如果 buffer 不是空字符串:

        1. portbuffer 以 radix-10 表示的数学整数值, 对值为 0 到 9 的数字使用 ASCII 数字

        2. 如果 port 不是一个 16 位无符号 整数port-out-of-range 验证错误,返回 失败。

        3. 如果 porturlscheme默认端口,则将 urlport 设为 null;否则设为 port

        4. buffer 设为空字符串。

        5. 如果给定了 state override,则返回。

      2. 如果给定了 state override,则返回失败。

      3. state 设为 路径开始状态,并将 pointer 减少 1。

    3. 否则,port-invalid 验证 错误,返回失败。

    文件状态
    1. urlscheme 设为 "file"。

    2. urlhost 设为空字符串。

    3. 如果 c 是 U+002F (/) 或 U+005C (\),则:

      1. 如果 c 是 U+005C (\),invalid-reverse-solidus 验证错误

      2. state 设为 文件斜杠状态

    4. 否则,如果 base 非 null,且 basescheme 是 "file":

      1. urlhost 设为 basehost, 将 urlpath 设为 basepath 的一个克隆,并将 urlquery 设为 basequery

      2. 如果 c 是 U+003F (?),则将 urlquery 设为空 字符串,并将 state 设为 查询状态

      3. 否则,如果 c 是 U+0023 (#),则将 urlfragment 设为 空字符串,并将 state 设为 片段 状态

      4. 否则,如果 c 不是 EOF 码点

        1. urlquery 设为 null。

        2. 如果从 pointerinput 末尾的 码点 子串不是以 Windows 驱动器盘符开头,则缩短 urlpath

        3. 否则:

          1. File-invalid-Windows-drive-letter 验证 错误

          2. urlpath 设为 « »。

          这是一个(与平台无关的)Windows 驱动器盘符怪癖。

        4. state 设为 路径状态 并将 pointer 减少 1。

    5. 否则,将 state 设为 路径状态,并将 pointer 减少 1。

    文件斜杠状态
    1. 如果 c 是 U+002F (/) 或 U+005C (\),则:

      1. 如果 c 是 U+005C (\),invalid-reverse-solidus 验证错误

      2. state 设为 文件主机状态

    2. 否则:

      1. 如果 base 非 null,且 basescheme 是 "file",则:

        1. urlhost 设为 basehost

        2. 如果从 pointerinput 末尾的码点 子串 不是以 Windows 驱动器盘符开头,且 basepath[0] 是一个 规范化的 Windows 驱动器盘符,则将 basepath[0] 追加urlpath

          这是一个(与平台无关的)Windows 驱动器盘符怪癖。

      2. state 设为 路径状态,并将 pointer 减少 1。

    文件主机状态
    1. 如果 cEOF 码点、U+002F (/)、U+005C (\)、 U+003F (?) 或 U+0023 (#),则将 pointer 减少 1,然后:

      1. 如果未给定 state override,且 buffer 是一个 Windows 驱动器盘符file-invalid-Windows-drive-letter-host 验证错误,将 state 设为 路径状态

        这是一个(与平台无关的)Windows 驱动器 盘符怪癖。buffer 在这里不重置,而是在路径状态中使用。

      2. 否则,如果 buffer 是空字符串,则:

        1. urlhost 设为空 字符串。

        2. 如果给定了 state override,则返回。

        3. state 设为 路径 开始状态

      3. 否则,运行这些步骤:

        1. host 为使用 url 不是特殊的,对 buffer 进行主机解析 的结果。

        2. 如果 host 为失败,则返回失败。

        3. 如果 host 是 "localhost",则将 host 设为 空字符串。

        4. urlhost 设为 host

        5. 如果给定了 state override,则返回。

        6. buffer 设为空字符串,并将 state 设为 路径开始状态

    2. 否则,将 c 追加到 buffer

    路径开始状态
    1. 如果 url 是特殊的,则:

      1. 如果 c 是 U+005C (\),invalid-reverse-solidus 验证错误

      2. state 设为 路径状态

      3. 如果 c 既不是 U+002F (/) 也不是 U+005C (\),则将 pointer 减少 1。

    2. 否则,如果未给定 state overridec 是 U+003F (?),则将 urlquery 设为空字符串,并将 state 设为 查询 状态

    3. 否则,如果未给定 state overridec 是 U+0023 (#),则将 urlfragment 设为空字符串,并将 state 设为 片段状态

    4. 否则,如果 c 不是 EOF 码点

      1. state 设为 路径状态

      2. 如果 c 不是 U+002F (/),则将 pointer 减少 1。

    5. 否则,如果给定了 state override,且 urlhost 为 null,则将空字符串追加urlpath

    路径状态
    1. 如果以下之一为 true:

      • cEOF 码点或 U+002F (/)

      • url 是特殊的,且 c 是 U+005C (\)

      • 未给定 state override,且 c 是 U+003F (?) 或 U+0023 (#)

      则:

      1. 如果 url 是特殊的,且 c 是 U+005C (\), invalid-reverse-solidus 验证错误

      2. 如果 buffer 是一个双点 URL 路径 片段,则:

        1. 缩短 urlpath

        2. 如果 c 不是 U+002F (/),且也不是 url 是特殊的并且 c 是 U+005C (\),则将空字符串追加urlpath

          这意味着对于输入 /usr/..,结果是 /, 而不是没有 path。

      3. 否则,如果 buffer 是一个单点 URL 路径 片段,并且 c 不是 U+002F (/), 且也不是 url 是特殊的并且 c 是 U+005C (\),则将空字符串 追加urlpath

      4. 否则,如果 buffer 不是一个单点 URL 路径 片段,则:

        1. 如果 urlscheme 是 "file",urlpath 为空,且 buffer 是一个 Windows 驱动器盘符, 则将 buffer 中的第二个码点替换为 U+003A (:)。

          这是一个(与平台无关的)Windows 驱动器盘符怪癖。

        2. buffer 追加urlpath

      5. buffer 设为空字符串。

      6. 如果 c 是 U+003F (?),则将 urlquery 设为空 字符串,并将 state 设为 查询状态

      7. 如果 c 是 U+0023 (#),则将 urlfragment 设为 空字符串,并将 state 设为 片段 状态

    2. 否则,运行这些步骤:

      1. 如果 c 不是一个URL 码点,也不是 U+0025 (%), invalid-URL-unit 验证错误

      2. 如果 c 是 U+0025 (%) 且 remaining 不是以两个 ASCII 十六进制数字开头,invalid-URL-unit 验证错误

      3. 使用 路径百分比编码集c 进行 UTF-8 百分比编码, 并将结果追加到 buffer

    不透明路径状态
    1. 如果 c 是 U+003F (?),则 将 urlquery 设为空 字符串,并将 state 设为 查询状态

    2. 否则,如果 c 是 U+0023 (#),则将 urlfragment 设为空字符串,并将 state 设为 片段状态

    3. 否则,如果 c 是 U+0020 SPACE:

      1. Invalid-URL-unit 验证错误

      2. 如果 remaining 以 U+003F (?) 或 U+0023 (#) 开头,则将 "%20" 追加到 urlpath

      3. 否则,将 U+0020 SPACE 追加到 urlpath

    4. 否则,如果 c 不是 EOF 码点

      1. 如果 c 不是一个URL 码点,也不是 U+0025 (%), invalid-URL-unit 验证错误

      2. 如果 c 是 U+0025 (%) 且 remaining 不是以两个 ASCII 十六进制数字开头,invalid-URL-unit 验证错误

      3. 使用 C0 控制 百分比编码集c 进行 UTF-8 百分比编码, 并将结果追加到 urlpath

    查询状态
    1. 如果 encoding 不是 UTF-8 且以下之一为 true:

      则将 encoding 设为 UTF-8

    2. 如果以下之一为 true:

      • 未给定 state override,且 c 是 U+0023 (#)

      • cEOF 码点

      则:

      1. 如果 url 是特殊的,则令 queryPercentEncodeSetspecial-query 百分比编码集;否则为查询百分比编码集

      2. 使用 encodingbufferqueryPercentEncodeSet,执行 编码后百分比编码, 并将结果追加到 urlquery

        由于有状态的 ISO-2022-JP 编码器,此操作不能 逐码点调用。

      3. buffer 设为空字符串。

      4. 如果 c 是 U+0023 (#),则将 urlfragment 设为 空字符串,并将 state 设为 片段 状态

    3. 否则,如果 c 不是 EOF 码点

      1. 如果 c 不是一个URL 码点,也不是 U+0025 (%), invalid-URL-unit 验证错误

      2. 如果 c 是 U+0025 (%) 且 remaining 不是以两个 ASCII 十六进制数字开头,invalid-URL-unit 验证错误

      3. c 追加到 buffer

    片段状态
    1. 如果 c 不是 EOF 码点,则:

      1. 如果 c 不是一个URL 码点,也不是 U+0025 (%), invalid-URL-unit 验证错误

      2. 如果 c 是 U+0025 (%) 且 remaining 不是以两个 ASCII 十六进制数字开头,invalid-URL-unit 验证错误

      3. 使用 片段百分比编码 集c 进行 UTF-8 百分比编码, 并将结果追加到 urlfragment

  10. 返回 url


要给定 urlusername 设置用户名,将 url用户名 设置为运行 UTF-8 百分比编码username 上,并使用 用户信息百分比编码集 的结果。

要给定 urlpassword 设置密码,将 url密码 设置为运行 UTF-8 百分比编码password 上,并使用 用户信息百分比编码集 的结果。

4.5. URL 序列化

URL 序列化器接受一个 URL url,带有一个 可选布尔值 exclude fragment(默认为 false),然后 运行 以下步骤。它们返回一个ASCII 字符串

  1. outputurl方案与 U+003A (:) 拼接的结果。

  2. 如果 url主机为非 null:

    1. 将 "//" 附加到 output

    2. 如果 url 包含凭据,则:

      1. url用户名附加到 output

      2. 如果 url密码不是空字符串, 则将 U+003A (:) 后跟 url密码附加到 output

      3. 将 U+0040 (@) 附加到 output

    3. url主机 序列化后的结果附加到 output

    4. 如果 url端口为非 null,则将 U+003A (:) 后跟 url端口序列化后的结果 附加到 output

  3. 如果 url主机为 null,url 不具有 不透明路径url路径大小大于 1,且 url路径[0] 是空字符串,则将 U+002F (/) 后跟 U+002E (.) 附加到 output

    这会防止 web+demo:/.//not-a-host/web+demo:/path/..//not-a-host/ 在被解析然后 序列化后,最终变成 web+demo://not-a-host/(它们 最终会成为 web+demo:/.//not-a-host/)。

  4. 将对 url 进行URL 路径序列化的结果附加到 output

  5. 如果 url查询为非 null,则将 U+003F (?) 后跟 url查询附加到 output

  6. 如果 exclude fragment 为 false,且 url片段为 非 null,则将 U+0023 (#) 后跟 url片段附加到 output

  7. 返回 output

URL 路径 序列化器接受一个 URL url,然后 运行这些步骤。它们返回一个ASCII 字符串

  1. 如果 url 有一个不透明路径,则返回 url路径

  2. output 为空字符串。

  3. 对于 url路径中的每个 segment 执行: 将 U+002F (/),后跟 segment,追加到 output

  4. 返回 output

4.6. URL 等价性

要确定 URL A 是否 等于 URL B,可选的布尔值 排除片段(默认为 false),请执行以下步骤:

  1. serializedA序列化 A 的结果,排除片段 设置为 排除片段

  2. serializedB序列化 B 的结果,排除片段 设置为 排除片段

  3. 如果 serializedA 等于 serializedB,则返回 true;否则返回 false。

4.7.

请参阅 HTML 中的定义,获取必要的背景信息。[HTML]

URL 的源是通过以下步骤,根据 url方案 切换得出的:

"blob"
  1. 如果 urlblob URL 项 非空,则返回 urlblob URL 项环境

  2. pathURL 设为解析 urlURL 路径序列化 结果的结果。

  3. 如果 pathURL 失败,则返回一个新的不透明源

  4. 如果 pathURL方案是 "http"、"https" 或 "file",则返回 pathURL

  5. 返回一个新的不透明源

blob:https://whatwg.org/d0360e2f-caee-469f-9a2f-87d5b0456f6f元组源 ("https"、"whatwg.org"、null、null)。

"ftp"
"http"
"https"
"ws"
"wss"

返回元组源(url方案url主机url端口、null)。

"file"

尽管令人遗憾,这个问题留给读者自行解决。当不确定时,返回一个新的不透明源

其他

返回一个新的不透明源

这确实意味着这些URL无法与自身成为同源

4.8. URL 渲染

当显示 URL 的主要目的是让用户做出安全或信任决定时,应该以其 序列化形式进行渲染,并进行如下所述的修改。例如,用户应根据浏览器地址栏中渲染的 URL 来做出信任决定。

4.8.1. 简化非人类可读或无关的组件

删除可能提供欺骗机会或分散安全相关信息的组件:

4.8.2. 省略

在空间受限的显示中,URL 应小心省略,以避免误导用户做出安全决定:

4.8.3. 国际化和特殊字符

国际化域名(IDN)、特殊字符和双向文本应谨慎处理,以防止欺骗:

5. application/x-www-form-urlencoded

application/x-www-form-urlencoded 格式提供了一种对 列表 中的 元组(每个元组包含一个名称和一个值)进行编码的方法。

application/x-www-form-urlencoded 格式在许多方面是一种异常的怪物,它是多年实现事故和妥协的结果,导致了一组为了互操作性而必需的要求,但绝不代表良好的设计实践。尤其是,读者应特别注意涉及字符编码和字节序列之间的多次(有时是嵌套的)转换的复杂细节。不幸的是,由于 HTML 表单的广泛使用,这种格式被广泛使用。[HTML]

5.1. application/x-www-form-urlencoded 解析

旧的面向服务器的实现可能必须支持 编码,如 UTF-8 以外的编码,以及对名称为 _charset 的元组进行特殊处理。此处未描述此类逻辑,因为仅 UTF-8 是合规的。

application/x-www-form-urlencoded 解析器 接受一个字节序列 input,然后运行以下步骤:

  1. sequences 设为通过 0x26 (&) 拆分 input 的结果。

  2. output 设为一个最初为空的名称-值元组的 列表,其中名称和值都存储为字符串。

  3. 对每个 字节序列 bytessequences 中:

    1. 如果 bytes 是空字节序列,则 继续

    2. 如果 bytes 包含 0x3D (=),则将 name 设为从 bytes 开头到其第一个 0x3D (=)(不包括)的字节,value 设为(如果有)从第一个 0x3D (=) 之后到 bytes 结尾的字节。如果 0x3D (=) 是第一个字节,则 name 将为空字节序列。如果是最后一个字节,则 value 将为空字节序列。

    3. 否则,将 name 设为 bytes 的值,并将 value 设为空字节序列。

    4. namevalue 中的任何 0x2B (+) 替换为 0x20 (SP)。

    5. nameStringvalueString 设为分别对 namevalue 进行无 BOM 的 UTF-8 解码百分比解码 的结果。

    6. (nameString, valueString) 附加到 output

  4. 返回 output

5.2. application/x-www-form-urlencoded 序列化

application/x-www-form-urlencoded 序列化器 接受一个名称-值元组的列表 tuples,可选地带有一个编码 encoding(默认 UTF-8),然后运行以下步骤。它们返回一个ASCII 字符串

  1. encoding 设置为通过 获取输出编码 获得的结果。

  2. output 设为空字符串。

  3. 对每个 tupletuples 中:

    1. 断言tuple 的 name 和 tuple 的 value 都是 标量值字符串

    2. name 为以 编码后百分号编码 配合 encodingtuple 的 name 和 application/x-www-form-urlencoded 百分号编码集 运行的结果。

    3. value 为以 编码后百分号编码 配合 encodingtuple 的 value 和 application/x-www-form-urlencoded 百分号编码集 运行的结果。

    4. 如果 output 不是空字符串,则追加 U+0026 (&) 到 output

    5. name、U+003D (=) 和 value 依次追加到 output
  4. 返回 output

5.3. 挂钩

application/x-www-form-urlencoded 字符串解析器 接受一个标量值字符串 inputUTF-8 编码 它,然后返回 application/x-www-form-urlencoded 解析 它的结果。

6. API

本节使用了 Web IDL 中的术语。浏览器用户代理必须支持此 API。JavaScript 实现应支持此 API。其他用户代理或编程语言则被鼓励使用适合其需求的 API,可能不是此 API。[WEBIDL]

6.1. URL 类

[Exposed=*,
 LegacyWindowAlias=webkitURL]
interface URL {
  constructor(USVString url, optional USVString base);

  static URL? parse(USVString url, optional USVString base);
  static boolean canParse(USVString url, optional USVString base);

  stringifier attribute USVString href;
  readonly attribute USVString origin;
           attribute USVString protocol;
           attribute USVString username;
           attribute USVString password;
           attribute USVString host;
           attribute USVString hostname;
           attribute USVString port;
           attribute USVString pathname;
           attribute USVString search;
  [SameObject] readonly attribute URLSearchParams searchParams;
           attribute USVString hash;

  USVString toJSON();
};

A URL 对象有一个关联的:

API URL 解析器 接受一个 标量值字符串 url 和一个可选的 null 或 标量值字符串 base(默认为 null),然后运行以下步骤:

  1. parsedBase 为 null。

  2. 如果 base 不为 null:

    1. parsedBase 设置为运行 基本 URL 解析器base 上的结果。

    2. 如果 parsedBase 失败,则返回失败。

  3. 返回运行 基本 URL 解析器urlparsedBase 上的结果。

为了 初始化 一个 URL 对象 url,给定一个 URL urlRecord

  1. queryurlRecord查询,如果它不是 null;否则为空字符串。

  2. urlURL 设置为 urlRecord

  3. url查询对象 设置为一个新的 URLSearchParams 对象。

  4. 初始化 url查询对象 使用 query

  5. url查询对象URL 对象 设置为 url

实现了 URL 接口的对象,其 提取起源 步骤为 返回 该对象URL起源[HTML]


new URL(url, base) 构造函数的步骤如下:

  1. parsedURL 设置为运行 API URL 解析器urlbase 上的结果,如果有提供 base

  2. 如果 parsedURL 失败,则 抛出一个 TypeError

  3. 初始化 this 使用 parsedURL

要在不使用 基础 URL的情况下,将字符串解析为一个URL,请使用单个参数调用 URL 构造函数:

var input = "https://example.org/💩",
    url = new URL(input)
url.pathname // "/%F0%9F%92%A9"

如果输入是相对 URL 字符串,则会抛出异常:

try {
  var url = new URL("/🍣🍺")
} catch(e) {
  // that happened
}

对于这些情况,必须有一个基础 URL

var input = "/🍣🍺",
    url = new URL(input, document.baseURI)
url.href // "https://url.spec.whatwg.org/%F0%9F%8D%A3%F0%9F%8D%BA"

URL 对象可以被 用作基础 URL (由于 IDL 要求参数是字符串, URL 对象 会字符串化为其 href getter 的返回值):

var url = new URL("🏳️‍🌈", new URL("https://pride.example/hello-world"))
url.pathname // "/%F0%9F%8F%B3%EF%B8%8F%E2%80%8D%F0%9F%8C%88"

静态方法 parse(url, base) 的步骤如下:

  1. parsedURL 设置为运行 API URL 解析器urlbase 上的结果,如果有提供 base

  2. 如果 parsedURL 失败,则返回 null。

  3. url 成为一个新的 URL 对象。

  4. 初始化 url,使用 parsedURL

  5. 返回 url

静态 canParse(url, base) 方法步骤如下:

  1. parsedURL 为对 url 以及给定的 base 执行 API URL 解析器 的结果。

  2. 如果 parsedURL 失败,则返回 false。

  3. 返回 true。


href getter 步骤和 toJSON() 方法步骤为,返回 序列化 后的 此对象URL

href setter 步骤如下:

  1. parsedURL 为对给定值运行 基本 URL 解析器 的结果。

  2. 如果 parsedURL 失败,则 抛出 TypeError

  3. 此对象URL 设为 parsedURL

  4. 清空 此对象query objectlist

  5. query此对象URLquery

  6. 如果 query 不为 null,则将 此对象query objectlist 设为 解析 query 的结果。

origin getter 步骤为返回 序列化此对象URLorigin[HTML]

protocol getter 步骤为返回 此对象URLscheme, 后跟 U+003A (:)。

protocol setter 步骤为 基本 URL 解析 给定值和 U+003A (:), 以 此对象URL 作为 url, 以 scheme start state 作为 state override

username getter 步骤为返回 此对象URLusername

username setter 步骤如下:

  1. 如果 此对象URL 不能有用户名/密码/端口,则返回。

  2. 此对象URL 和给定值 设置用户名

password getter 步骤为返回 此对象URLpassword

password setter 步骤如下:

  1. 如果 此对象URL 不能有用户名/密码/端口,则返回。

  2. 此对象URL 和给定值 设置密码

host getter 步骤为:

  1. urlthisURL

  2. 如果 url主机为 null,则返回空字符串。

  3. 如果 url端口为 null,则返回 url主机序列化结果。

  4. 返回 url主机序列化结果, 后跟 U+003A (:) 和 url端口序列化结果。

host setter 步骤为:

  1. 如果 thisURL具有不透明路径,则返回。

  2. 对给定值执行基本 URL 解析,并以 thisURL 作为url,以主机状态作为 state override

如果给 host setter 的给定值缺少 端口thisURL端口不会 改变。这可能出乎意料,因为 host getter 确实会返回一个URL-端口字符串,所以 人们可能会以为 setter 总是会“重置”二者。

hostname getter 步骤为:

  1. 如果 thisURL主机为 null,则返回空 字符串。

  2. 返回 thisURL主机序列化结果。

hostname setter 步骤是:

  1. 如果 thisURL 有一个不透明路径,则返回。

  2. 使用给定值进行基本 URL 解析,其中 thisURL 作为 url主机名状态作为 state override

port getter 步骤是:

  1. 如果 thisURL端口为 null,则返回空 字符串。

  2. 返回 thisURL端口 序列化后的结果。

port setter 步骤是:

  1. 如果 thisURL 不能有用户名/密码/端口, 则 返回。

  2. 如果给定值是空字符串,则将 thisURL端口设为 null。

  3. 否则,使用给定值进行基本 URL 解析,其中 thisURL 作为 url,并且 端口状态作为 state override

pathname getter 步骤是返回对 thisURL进行URL 路径 序列化的结果。

pathname setter 步骤是:

  1. 如果 thisURL 有一个不透明路径,则返回。

  2. 清空 thisURL路径

  3. 使用给定值进行基本 URL 解析,其中 thisURL 作为 url路径起始状态作为 state override

search getter 步骤是:

  1. 如果 thisURL查询为 null 或空 字符串,则返回空字符串。

  2. 返回 U+003F (?),后跟 thisURL查询

search setter 步骤是:

  1. urlthisURL

  2. 如果给定值是空字符串,则将 url查询设为 null,清空 this查询对象列表,并返回。

  3. input 为移除了单个前导 U+003F (?)(如果有)的给定值。

  4. url查询设为空字符串。

  5. 使用 input 进行基本 URL 解析,其中 url 作为 url查询状态作为 state override

  6. this查询对象列表设为 解析 input 的 结果。

searchParams getter 步骤是返回 this查询 对象

hash getter 步骤是:

  1. 如果 thisURL片段为 null 或空 字符串,则返回空字符串。

  2. 返回 U+0023 (#),后跟 thisURL片段

hash setter 步骤是:

  1. 如果给定值是空字符串,则将 thisURL片段设为 null 并返回。

  2. input 为移除了单个前导 U+0023 (#)(如果有)的给定值。

  3. thisURL片段设为空 字符串。

  4. 使用 input 进行基本 URL 解析,其中 thisURL 作为 url片段状态作为 state override

6.2. URLSearchParams 类

[Exposed=*]
interface URLSearchParams {
  constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = "");

  readonly attribute unsigned long size;

  undefined append(USVString name, USVString value);
  undefined delete(USVString name, optional USVString value);
  USVString? get(USVString name);
  sequence<USVString> getAll(USVString name);
  boolean has(USVString name, optional USVString value);
  undefined set(USVString name, USVString value);

  undefined sort();

  iterable<USVString, USVString>;
  stringifier;
};

构造并序列化一个 URLSearchParams 对象非常简单:

let params = new URLSearchParams({key: "730d67"})
params.toString() // "key=730d67"

由于 URLSearchParams 对象底层使用 application/x-www-form-urlencoded 格式,因此它对某些代码点的编码方式与 URL 对象(包括 hrefsearch)相比存在一些差异。当使用 searchParams 操作 URL查询时,这一点尤其令人惊讶。

const url = new URL('https://example.com/?a=b ~');
console.log(url.href);   // "https://example.com/?a=b%20~"
url.searchParams.sort();
console.log(url.href);   // "https://example.com/?a=b+%7E"
const url = new URL('https://example.com/?a=~&b=%7E');
console.log(url.search);                // "?a=~&b=%7E"
console.log(url.searchParams.get('a')); // "~"
console.log(url.searchParams.get('b')); // "~"

URLSearchParams 对象会对 application/x-www-form-urlencoded percent-encode set 中的任何字符进行百分比编码,并将 U+0020 SPACE 编码为 U+002B (+)。

忽略编码(使用 UTF-8),search 将对查询百分比编码集特殊查询百分比编码集中的任何内容进行百分比编码(取决于URL 是否特殊)。

一个 URLSearchParams 对象具有一个关联的:

初始化一个 URLSearchParams 对象 query(使用 init):

  1. 如果 init 是一个序列, 则对于 init 中的每个 innerSequence

    1. 如果 innerSequence大小 不是 2,则抛出一个 TypeError

    2. 将 (innerSequence[0], innerSequence[1]) 追加query列表中。

  2. 否则,如果 init 是一个记录,则对于 init 中的每个 namevalue, 将 (name, value) 追加query列表中。

  3. 否则:

    1. 断言:init 是一个字符串。

    2. query列表设置为解析 init 的结果。

更新一个 URLSearchParams 对象 query

  1. 如果 queryURL 对象为 null,则返回。

  2. serializedQueryquery列表序列化结果。

  3. 如果 serializedQuery 是空字符串,则将 serializedQuery 设置为 null。

  4. queryURL 对象URL查询设置为 serializedQuery

new URLSearchParams(init) 构造函数的步骤是:

  1. 如果 init 是一个字符串且以 U+003F (?) 开头,则从 init 中移除第一个代码点。

  2. 使用 init 初始化此对象

size getter 的步骤是返回此对象列表大小

append(name, value) 方法的步骤是:

  1. 将 (name, value) 追加此对象列表中。

  2. 更新此对象

delete(name, value) 方法的步骤是:

  1. 如果给定了 value,则移除所有 元组,其名称为 name 且值为 value,从此对象列表中。

  2. 否则,移除所有元组,其名称为 name,从 此对象列表中。

  3. 更新此对象

get(name) 方法的步骤为: 返回 此对象列表中第一个名称为 name元组的值;如果没有这样的 元组,则返回 null。

getAll(name) 方法的步骤为: 以列表顺序返回 此对象列表中所有名称为 name元组的值;否则返回空序列。

has(name, value) 方法的步骤如下:

  1. 若给定 value此对象列表中存在名称为 name 且值为 value元组,则返回 true。

  2. 若未给定 value此对象列表中存在名称为 name元组,则返回 true。

  3. 返回 false。

set(name, value) 方法的步骤如下:

  1. 此对象列表 包含任何名称为 name元组,则将第一个该 元组的值设为 value,并移除其它同名元组。

  2. 否则,追加 (name, value) 到 此对象列表中。

  3. 更新此对象


URLSearchParams 对象中的 name-value 元组进行排序在某些情况下是有用的,尤其可以提高缓存命中率。可以通过调用 sort() 方法实现:

const url = new URL("https://example.org/?q=🏳️‍🌈&key=e1f7bc78");
url.searchParams.sort();
url.search; // "?key=e1f7bc78&q=%F0%9F%8F%B3%EF%B8%8F%E2%80%8D%F0%9F%8C%88"

为了避免修改原始输入,比如用于比较,可以新建一个 URLSearchParams 对象:

const sorted = new URLSearchParams(url.search)
sorted.sort()

sort() 方法的步骤如下:

  1. 此对象列表设置为 升序排序此对象列表a 小于 b 的条件为 a 的名称 码元小于 b 的名称。

  2. 更新此对象


可迭代的键值对此对象列表中的 元组,键为名称,值为 value。

字符串化行为的步骤为:返回 序列化此对象列表

6.3. 其他标准中的 URL API

暴露 URL 的标准,应当以字符串形式暴露 URL(通过对内部 URL 进行 序列化)。标准不应当使用 URL 对象来暴露 URLURL 对象仅用于 URL 操作。在 IDL 中应使用 USVString 类型。

这里的高层次概念是值应当作为不可变的数据结构公开。

如果某标准决定使用 "URL" 名称的变体来定义其功能,建议将此功能命名为 "url"(即小写,并且以 "l" 结尾)。不应使用 "URL"、"URI" 和 "IRI" 等名称。然而,如果名称是复合词,建议使用 "URL"(即大写),例如 "newURL" 和 "oldURL"。

接口 EventSourceHashChangeEventHTML 中正确命名的示例。 [HTML]

致谢

多年来,许多人帮助使 URL 变得更加互操作,从而推动了本标准的目标。同样,许多人帮助将本标准发展成今天的样子。

在此,特别感谢以下人士: 100の人, Adam Barth, Addison Phillips, Adrián Chaves, Adrien Ricciardi, Albert Wiersch, Alex Christensen, Alexandre Morgaut, Alexis Hunt, Alwin Blok, Andrew Sullivan, Arkadiusz Michalski, Behnam Esfahbod, Bobby Holley, Boris Zbarsky, Brad Hill, Brandon Ross, Cailyn Hansen, Chris Dumez, Chris Rebert, Corey Farwell, Dan Appelquist, Daniel Bratell, Daniel Stenberg, David Burns, David Håsäther, David Sheets, David Singer, David Walp, Domenic Denicola, Emily Schechter, Emily Stark, Eric Lawrence, Erik Arvidsson, Gavin Carothers, Geoff Richards, Glenn Maynard, Gordon P. Hemsley, hemanth, Henri Sivonen, Ian Hickson, Ilya Grigorik, Italo A. Casas, Jakub Gieryluk, James C. Wise, James Graham, James Manger, James Ross, Jeff Hodges, Jeffrey Posnick, Jeffrey Yasskin, Joe Duarte, Joshua Bell, Jxck, Karl Wagner, Kemal Zebari, 田村健人 (Kent TAMURA), Kevin Grandon, Kornel Lesiński, Larry Masinter, Leif Halvard Silli, Mark Amery, Mark Davis, Marcos Cáceres, Marijn Kruisselbrink, Martin Dürst, Mathias Bynens, Matt Falkenhagen, Matt Giuca, Michael Peick, Michael™ Smith, Michal Bukovský, Michel Suignard, Mikaël Geljić, Nikita Skovoroda, Noah Levitt, Peter Occil, Philip Jägenstedt, Philippe Ombredanne, Prayag Verma, Rimas Misevičius, Robert Kieffer, Rodney Rehm, Roy Fielding, Ryan Sleevi, Sam Ruby, Sam Sneddon, Santiago M. Mola, Sebastian Mayr, Shannon Booth, Simon Pieters, Simon Sapin, Steven Vachon, Stuart Cook, Sven Uhlig, Tab Atkins, 吉野剛史 (Takeshi Yoshino), Tantek Çelik, Tiancheng "Timothy" Gu, Tim Berners-Lee, 簡冠庭 (Tim Guan-tin Chien), Titi_Alone, Tomek Wytrębowicz, Trevor Rowbotham, Tristan Seligmann, Valentin Gosu, Vyacheslav Matva, Wei Wang, Wolf Lammen, 山岸和利 (Yamagishi Kazutoshi), Yongsheng Zhang, 成瀬ゆい (Yui Naruse),以及 zealousidealroll, 你们真棒!

本标准由 Anne van Kesteren 编写(Apple[email protected])。

知识产权

版权 © WHATWG (Apple, Google, Mozilla, Microsoft)。此作品依据 知识共享署名 4.0 国际许可协议 授权。若本作品的部分内容被纳入源代码,则源代码部分依据 BSD 3-Clause 许可协议 授权。

这是现行标准。对专利审核版感兴趣的用户可以查看 现行标准审核草案

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[BIDI]
Manish Goregaokar मनीष गोरेगांवकर;Robin Leroy。Unicode 双向算法。 2025年8月13日。Unicode 标准附件 #9。URL:https://www.unicode.org/reports/tr9/tr9-51.html
[ENCODING]
Anne van Kesteren. 编码标准。现行标准。URL: https://encoding.spec.whatwg.org/
[FILEAPI]
Marijn Kruisselbrink. 文件 API。URL: https://w3c.github.io/FileAPI/
[HTML]
Anne van Kesteren 等人。HTML 标准。现行标准。URL: https://html.spec.whatwg.org/multipage/
[IANA-URI-SCHEMES]
统一资源标识符 (URI) 方案。URL: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
[INFRA]
Anne van Kesteren; Domenic Denicola. 基础结构标准。现行标准。URL: https://infra.spec.whatwg.org/
[PSL]
公共后缀列表。URL:https://publicsuffix.org/
[UTS46]
Mark Davis;Markus Scherer。Unicode IDNA 兼容性处理。2025年9月4日。Unicode 技术标准 #46。URL:https://www.unicode.org/reports/tr46/tr46-35.html
[WEBIDL]
Edgar Chen;Timothy Gu。Web IDL 标准。Living Standard。URL:https://webidl.spec.whatwg.org/

非规范性引用

[ECMA-262]
ECMAScript 语言规范。URL:https://tc39.es/ecma262/multipage/
[IDNFAQ]
国际化域名(IDN)常见问题。URL: https://unicode.org/faq/idn.html
[RFC1034]
P. Mockapetris。域名 - 概念与 设施。1987 年 11 月。互联网标准。URL:https://www.rfc-editor.org/info/rfc1034/
[RFC3986]
T. Berners-Lee; R. Fielding; L. Masinter。统一 资源标识符(URI):通用语法。2005 年 1 月。互联网标准。URL:https://www.rfc-editor.org/info/rfc3986/
[RFC3987]
M. Duerst; M. Suignard。国际化资源 标识符(IRI)。2005 年 1 月。提议标准。URL:https://www.rfc-editor.org/info/rfc3987/
[RFC4291]
R. Hinden; S. Deering。IP 版本 6 地址 架构。2006 年 2 月。草案标准。URL:https://www.rfc-editor.org/info/rfc4291/
[RFC5890]
J. Klensin。应用中的国际化域名 (IDNA):定义与文档框架。2010 年 8 月。提议标准。 URL:https://www.rfc-editor.org/info/rfc5890/
[RFC5952]
S. Kawamura; M. Kawashima。IPv6 地址 文本表示的建议。2010 年 8 月。提议标准。URL:https://www.rfc-editor.org/info/rfc5952/
[RFC6454]
A. Barth。Web 源概念。 2011 年 12 月。提议标准。URL:https://www.rfc-editor.org/info/rfc6454/
[RFC7595]
D. Thaler, Ed.; T. Hansen; T. Hardie。URI 方案的 指南和注册程序。2015 年 6 月。最佳当前实践。URL:https://www.rfc-editor.org/info/rfc7595/
[RFC791]
J. Postel。互联网协议。1981 年 9 月。 互联网标准。URL:https://www.rfc-editor.org/info/rfc791/
[UTR36]
Mark Davis; Michel Suignard。Unicode 安全考虑。2014 年 9 月 19 日。Unicode 技术报告 #36。URL:https://www.unicode.org/reports/tr36/tr36-15.html
[UTS39]
Mark Davis; Michel Suignard。Unicode 安全机制。2025 年 9 月 4 日。Unicode 技术标准 #39。URL:https://www.unicode.org/reports/tr39/tr39-32.html

IDL 索引

[Exposed=*,
 LegacyWindowAlias=webkitURL]
interface URL {
  constructor(USVString url, optional USVString base);

  static URL? parse(USVString url, optional USVString base);
  static boolean canParse(USVString url, optional USVString base);

  stringifier attribute USVString href;
  readonly attribute USVString origin;
           attribute USVString protocol;
           attribute USVString username;
           attribute USVString password;
           attribute USVString host;
           attribute USVString hostname;
           attribute USVString port;
           attribute USVString pathname;
           attribute USVString search;
  [SameObject] readonly attribute URLSearchParams searchParams;
           attribute USVString hash;

  USVString toJSON();
};

[Exposed=*]
interface URLSearchParams {
  constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = "");

  readonly attribute unsigned long size;

  undefined append(USVString name, USVString value);
  undefined delete(USVString name, optional USVString value);
  USVString? get(USVString name);
  sequence<USVString> getAll(USVString name);
  boolean has(USVString name, optional USVString value);
  undefined set(USVString name, USVString value);

  undefined sort();

  iterable<USVString, USVString>;
  stringifier;
};

MDN

URL/URL

In all current engines.

Firefox26+Safari14.1+Chrome19+
Opera?Edge79+
Edge (Legacy)12+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js10.0.0+
MDN

URL/canParse_static

Firefox115+Safari17+ChromeNone
Opera?EdgeNone
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js20.0.0+
MDN

URL/hash

In all current engines.

Firefox22+Safari7+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/host

In all current engines.

Firefox22+Safari7+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/hostname

In all current engines.

Firefox22+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/href

In all current engines.

Firefox22+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/origin

In all current engines.

Firefox26+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)12+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet6.0+Opera Mobile?
Node.js7.0.0+
MDN

URL/password

In all current engines.

Firefox26+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)12+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet6.0+Opera Mobile?
Node.js7.0.0+
MDN

URL/pathname

In all current engines.

Firefox22+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/port

In all current engines.

Firefox22+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/protocol

In all current engines.

Firefox22+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/search

In all current engines.

Firefox22+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.0.0+
MDN

URL/searchParams

In all current engines.

Firefox29+Safari10.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URL/toJSON

In all current engines.

Firefox54+Safari11+Chrome71+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.7.0+
MDN

URL/toString

In all current engines.

Firefox54+Safari7+Chrome19+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet6.0+Opera Mobile?
Node.js7.0.0+
MDN

URL/username

In all current engines.

Firefox26+Safari10+Chrome32+
Opera?Edge79+
Edge (Legacy)12+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet6.0+Opera Mobile?
Node.js7.0.0+
MDN

URL

In all current engines.

Firefox19+Safari7+Chrome32+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile?
Node.js10.0.0+
MDN

URLSearchParams/URLSearchParams

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+

URLSearchParams/entries

In all current engines.

Firefox44+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+

URLSearchParams/forEach

In all current engines.

Firefox44+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+

URLSearchParams/keys

In all current engines.

Firefox44+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+

URLSearchParams/values

In all current engines.

Firefox44+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams/append

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams/delete

In all current engines.

Firefox29+Safari14+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams/get

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams/getAll

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams/has

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams/set

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams/size

In all current engines.

Firefox112+Safari17+Chrome113+
Opera?Edge113+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js19.0.0+
MDN

URLSearchParams/sort

In all current engines.

Firefox54+Safari11+Chrome61+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.7.0+
MDN

URLSearchParams/toString

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js7.5.0+
MDN

URLSearchParams

In all current engines.

Firefox29+Safari10.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js10.0.0+