1. 什么是URI?
1.1. URI
URI,全称为 统一资源标识符,是一个更广义的概念。它的核心作用是标识一个资源。
1.2. URL
URL,全称为 统一资源定位符,它是 URI 的一个子集(或者说是一种具体类型)。它的核心作用是定位一个资源,即告诉你如何以及在哪里可以访问到这个资源。
1.3. URN
URN,全称为 统一资源名称,它也是 URI 的一个子集。它的核心是给资源一个永久的、与位置无关的名称。
1.4. 三者之间的关系
我们以书籍的例子来做一个比喻:
- URI 是广义的“标识”概念。
 - URL 是“住址”,依赖于位置。
 - URN 是“身份证号”,是永久的名称,不依赖于位置。
 
例子:
- URN:
urn:isbn:978-7-505-12345-6(这是一本书的 URN) - URL:
https://example-library.com/books/978-7-505-12345-6.pdf(这是这本书在当前图书馆的电子版位置) 
即使图书馆的网站倒闭了,这个 URN 依然有效,它永远指向那本特定的书。但那个 URL 就失效了,因为你找不到那个位置了。
2. URI的编码与解码
2.1. 为什么需要 URI 编码?
URI 是由一组有限的字符组成的:
- 保留字符:如 
:,/,?,#,&,=,+,$等,它们在 URI 中有特殊含义。 - 非保留字符:如字母(A-Z, a-z)、数字(0-9)以及 
-,_,.,~。 - 其他字符:如空格、中文、日文等非 ASCII 字符,以及像 
<,>,"等。 
如果 URI 中包含这些“其他字符”或者需要在参数值中使用“保留字符”,就会引起歧义,导致 URI 无法被正确解析。
例如:
如果你想传递一个参数 name,其值为 "O‘Reilly & Associates"。
1  | https://example.com/search?name=O’Reilly & Associates  | 
这个 URL 会被解析为:
- 路径:
/search - 查询参数1:
name=O’Reilly - 查询参数2:
Associates(一个没有值的参数) 
这显然不是我们想要的结果。为了解决这个问题,我们需要对不安全的字符进行编码(Encode)。
2.2. URI是如何编码的?
URI 编码,也称为百分比编码,其机制非常简单:
- 将需要编码的字符转换成其 UTF-8 编码的字节序列。
 - 然后将每个字节表示为一个 
%XX的格式,其中XX是该字节的十六进制数字。 
说明: 解码的过程与编码的过程正好相反,就是编码的逆过程。
例如:
- 空格:其 UTF-8 字节是 
0x20(十进制是32),所以编码后是%20。在查询字符串中,+号也常被用来代表空格。 - 中文字符 “中”:
- 它的 UTF-8 编码是 3 个字节:
0xE4,0xB8,0xAD。 - 所以编码后是 
%E4%B8%AD。 
 - 它的 UTF-8 编码是 3 个字节:
 - 符号 “&”:其字节是 
0x26,编码后是%26。 
现在,用编码来解决上面的例子:
原始值:O’Reilly & Associates
编码后:O%27Reilly%20%26%20Associates
(’ 被编码为 %27,空格为 %20,& 为 %26)
现在 URL 就安全了:
1  | https://example.com/search?name=O%27Reilly%20%26%20Associates  | 
3. 编码与解码函数
3.1. encodeURI 与 encodeURIComponent
在JavaScript中,有两个核心的URI编码函数:encodeURI() 和 encodeURIComponent()。它们的主要区别在于编码范围的不同,这直接决定了它们各自的使用场景。
- **
encodeURI()**:- 用于编码完整的 URI。它假设输入的是一个完整的 URL,因此会保留那些在 URI 中具有特殊含义的保留字符。
 - 对应的解码函数是 
decodeURI()。 
 - **
encodeURIComponent()**:- 用于编码 URI 的组成部分(比如查询参数的值、路径片段等)。它会把几乎所有非标准字符都编码掉,包括保留字符。
 - 对应的解码函数是 
decodeURIComponent()。 
 
3.2. 编码的区别
这是理解两者区别的关键。下表清晰地展示了它们对待不同字符的行为:
| 字符类型 | 示例字符 | encodeURI | 
encodeURIComponent | 
原因 | 
|---|---|---|---|---|
| 保留字符 | ; / ? : @ & = + $ , # | 
保留 | 编码 | 这些字符在 URI 各部分有特殊作用,不能乱编码。 | 
| 非保留字符 | 字母、数字、- _ . ! ~ * ' ( ) | 
保留 | 保留 | 这些是安全的,不需要编码。 | 
| 未保留字符(但有例外) | 空格 | %20 | 
%20 (或 + 在 application/x-www-form-urlencoded 中) | 
空格是非法的,必须编码。 | 
| 其他所有字符 | 中文、表情等 Unicode 字符 | 编码 | 编码 | 这些字符必须转换为 UTF-8 字节后再进行百分比编码。 | 
简单记忆:
encodeURIComponent比encodeURI编码得更多、更彻底。encodeURI只编码那些在任何 URI 部分都非法的字符(如空格、中文字符)。encodeURIComponent会编码所有在它所在组件中可能引起歧义的字符(包括保留字符)。