URI 处理函数

22 天前
2

URI 处理函数

URI(Uniform Resource Identifier,统一资源标识符)是用于标识资源(如网页、文件)和传输协议(如 HTTP、FTP)的字符串。ECMAScript 提供了四个用于编码和解码 URI 的内置函数,以及三个底层抽象操作。


一、编码函数

1.1 encodeURI(uri)

对完整 URI 进行编码,保留 URI 中的保留字符。

特点:

  • 假设保留字符具有特殊含义(如作为分隔符),因此不进行编码
  • 用于编码完整的 URI

保留字符(不编码): ;/?:@&=+$,#

encodeURI("https://example.com/path?name=张三")
// "https://example.com/path?name=%E5%BC%A0%E4%B8%89"

1.2 encodeURIComponent(uriComponent)

对 URI 组件进行编码,编码所有保留字符。

特点:

  • 假设保留字符只是普通文本,需要编码以避免在 URI 中产生特殊含义
  • 用于编码 URI 的单个组成部分

保留字符(全部编码): 无(空字符串)

encodeURIComponent("张三")
// "%E5%BC%A0%E4%B8%89"

encodeURIComponent("name=value")
// "name%3Dvalue"

二、解码函数

2.1 decodeURI(encodedURI)

对由 encodeURI 编码的 URI 进行解码。

特点:

  • 保留 ;/?:@&=+$,# 这些字符的编码形式
  • 不会解码非 encodeURI 产生的编码
decodeURI("https://example.com/path?name=%E5%BC%A0%E4%B8%89")
// "https://example.com/path?name=张三"

2.2 decodeURIComponent(encodedURIComponent)

对 URI 组件进行解码。

特点:

  • 解码所有 percent 编码
  • 用于解码由 encodeURIComponent 编码的字符串
decodeURIComponent("%E5%BC%A0%E4%B8%89")
// "张三"

三、底层抽象操作

3.1 Encode(string, extraUnescaped)

将字符串进行 URI 编码的抽象操作。

参数:

  • string: 要编码的字符串
  • extraUnescaped: 额外的未转义字符

算法步骤:

  1. 定义 alwaysUnescaped: ASCII 字母数字字符 + - . ! ~ * ' ( )
  2. 合并 unescapedSet = alwaysUnescaped + extraUnescaped
  3. 遍历字符串的每个码点:
    • 如果字符在 unescapedSet 中,不编码
    • 否则,转换为 UTF-8 编码的字节序列,每个字节转为 %XX 形式
  4. 如果遇到未配对的代理码,抛出 URIError

示例: javascript // encodeURI 内部调用 Encode(string, ";/?:@&=+$,#") // encodeURIComponent 内部调用 Encode(string, "")

3.2 Decode(string, preserveEscapeSet)

将 URI 编码字符串解码的抽象操作。

参数:

  • string: 要解码的字符串
  • preserveEscapeSet: 需要保留编码形式的字符集

算法步骤:

  1. 遍历字符串:
    • 遇到普通字符,直接追加
    • 遇到 %
      • 读取后续两个十六进制字符
      • 如果是 ASCII 字符且在 preserveEscapeSet 中,保留 %XX 形式
      • 否则,解码为对应字符
  2. 多字节 UTF-8 序列处理:
    • 根据首字节的前导 1 位数量确定后续字节数
    • 验证后续字节格式(必须以 % 开头)
    • 将完整的 UTF-8 字节序列解码为 Unicode 码点
    • 如果是无效 UTF-8,抛出 URIError

注意: RFC 3629 禁止解码无效的 UTF-8 序列,例如 0xC0 0x80 不能解码为 0x0000

3.3 ParseHexOctet(string, position)

解析字符串指定位置的两个十六进制字符为无符号 8 位整数。

参数:

  • string: 输入字符串
  • position: 起始位置

返回: 0-255 之间的整数,或 SyntaxError


四、函数对比

函数用途保留字符适用场景
encodeURI编码完整 URI;/?:@&=+$,#编码整个 URL
encodeURIComponent编码 URI 组件编码 URL 参数、路径片段
decodeURI解码完整 URI;/?:@&=+$,#解码由 encodeURI 编码的字符串
decodeURIComponent解码 URI 组件解码任意 percent 编码

五、编码对照表

不编码的字符(alwaysUnescaped)

A-Z a-z 0-9 - . ! ~ * ' ( )

encodeURI 额外不编码

; / ? : @ & = + $ , #

特殊字符编码示例

字符encodeURIencodeURIComponent
空格%20%20
中文%E5%BC%A0%E5%BC%A0
==%3D
##%23
//%2F

六、常见错误

6.1 URIError

  • 无效的 percent 编码:如 %GG
  • 不完整的转义序列:如 %20 后没有足够字符
  • 无效的 UTF-8 序列:如过短的续字节
  • 未配对的代理码:在编码时遇到孤立的 surrogate

6.2 常见误用

// 错误:URL 查询参数应该用 encodeURIComponent
const url = "https://example.com?param=" + encodeURI("张三");
// 正确
const url = "https://example.com?param=" + encodeURIComponent("张三");

七、总结

  1. 编码选择

    • 编码整个 URL → encodeURI
    • 编码 URL 参数值 → encodeURIComponent
  2. 解码选择

    • 解码完整 URL → decodeURI
    • 解码任意编码字符串 → decodeURIComponent
  3. 底层实现

    • EncodeDecode 是核心算法
    • ParseHexOctet 用于解析十六进制字节
  4. UTF-8 编码:JavaScript 内部使用 UTF-16 字符串,编码时需转换为 UTF-8 字节序列


参考

  • ECMAScript 2025 Language Specification
  • RFC 2396 (URI Generic Syntax)
  • RFC 3629 (UTF-8)

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...